skip to Main Content

Here I am using server component for Search form but to able to empty the input field when user click the cancel button I import a <SearchReset/> which is a client component but i cant reset or empty the form.

SearchForm.tsx

;<Form
  action="/search"
  className="search-form input input-bordered flex items-center gap-2 bg-white py-2 px-4 max-w-md mx-auto rounded border-2"
>
  <input
    name="query"
    defaultValue={query}
    className="search-input grow w-full focus:outline-none outline-none focus:ring-0 active:ring-0"
    placeholder="Seacrh Ideas"
  />

  {query ? (
    <SearchReset />
  ) : (
    <button type="submit" className="flex items-center">
      <Search className="text-secondary size-6" />
    </button>
  )}
</Form>

SearchReset.tsx

export default function SearchReset () {
  const reset = () => {
    const form = document.querySelector(".search-form") as HTMLFormElement
    console.log(form)
    if (form) {
      const input = form.querySelector(
        'input[name="query"]',
      ) as HTMLInputElement
      console.log(input) // this works
      if (input) {
        input.value = "" // this doesnt
      }
      form.reset()
    }
  }

  return (
    <button type="reset" className="flex items-center" onClick={reset}>
      <X className="text-black-200 size-4" />
    </button>
  )
}

I tried to access the form’s input field after I click the reset button which I can but when am trying to set it’s value empty or reset the form it’s not working

2

Answers


  1. There are two states that you want to change here.

    1. The url query state in the address bar after resetting. ex: from
      /search?query=something to /search.
    2. the input field has to be emptied.

    You can do the first by keeping the form a server component, because the state you’re changing is outside the component itself.

    But for the second one you can’t.

    This isn’t possible with server components. as a thumb rule. whenever you want to update the state of a server component, then it means it has to be converted to a client component. So, your <SearchForm /> component will have to become a client component by using the 'use client' directive. After you do that, you’ll no longer need all of those tricky things to get around it, like using querySelectors in your <SearchReset /> component.

    It’s not a bad thing to make a client component! it’s a normal thing that happens all the time, usually forms are almost always client components due to their intensive reactivity.

    for example some people like to make validation on the fly, some folks format the currencies, some people use react-hook-form so it’s completely normal to have almost all your forms in your website as client components, for myself I never had a complete server form component, everything around the form is usually static, but the form itself is almost always a client component.

    For anything else, you keep them server components, only when you have an interactive part, you make that small part a client component. But in your case this isn’t the case, because not only the button is a reactive component, also the input field as well.

    since almost everything inside the <Form> is gonna become a client components, then it would be so much weird to have the <Form> alone a server component. So, move your Form to a separate file and make it a client component, for the page, keep your pages always server components.

    This is the easiest solution and everyone do this.

    Here’s how this would look like after the modifications:

    .
    ├── src
    │   ├── app
    │   │   ├── layout.tsx
    │   │   └── search
    │   │       └── page.tsx 👈
    │   └── components
    │       ├── search-form.tsx 👈
    │       └── search-reset.tsx ❌ as u wish, but it's no longer necessary
    ├── tailwind.config.ts
    └── tsconfig.json
    

    File: src/app/search/page.tsx

    import SearchForm from '@/components/search-form'
    import React from 'react'
    
    const page = ({ searchParams }: { searchParams: { query: string } }) => {
      return (
        <React.Fragment>
          <SearchForm query={searchParams.query} />
        </React.Fragment>
      )
    }
    
    export default page
    
    

    File: src/components/search-form.tsx

    'use client'
    
    import Form from 'next/form'
    import React, { useState } from 'react'
    import { useRouter } from 'next/navigation'
    
    export interface SearchFormProps {
      query?: string
    }
    
    export const SearchForm = (props: SearchFormProps) => {
      const { query = '' } = props
      const [searchStr, setSearchStr] = useState(query)
      const router = useRouter()
      const reset = () => {
        router.back()
        setSearchStr('')
      }
    
      return (
        <Form
          action="/search"
          className="search-form input input-bordered flex items-center gap-2 bg-white py-2 px-4 max-w-md mx-auto rounded border-2"
        >
          <input
            name="query"
            className="search-input grow w-full focus:outline-none outline-none focus:ring-0 active:ring-0"
            placeholder="Seacrh Ideas"
            value={searchStr}
            onChange={(e) => setSearchStr(e.target.value)}
          />
    
          {query ? (
            <button type="reset" className="flex items-center" onClick={reset}>
              Reset
            </button>
          ) : (
            <button className="flex items-center">Search</button>
          )}
        </Form>
      )
    }
    
    export default SearchForm
    
    
    Login or Signup to reply.
  2. In your code you reset searchStr to ”, but you didn’t reset query value. That is probably the issue

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search