skip to Main Content

I have a page with a form. I want to store the values of the form in the url so they can persist even if you accidentally refresh the page.

// Form.tsx
"use client"
export default function Form(){
    const pathname = usePathname()
    const searchParams = useSearchParams()
    const router = useRouter()
    
    const [content, setContent] = useState(searchParams.get("content") || "")
    
    useEffect(() => {
        const newSearchParams = new UrlSearchParams({ content })
        router.replace(pathname + "?" + newSearchParams.toString(), { scroll: false })
    }, [content, pathname, router])

    return <div>
        // Form ui here
    </div>

}

// page.tsx
export default async function Page(){
    const data = await getData() // fetches data from db
    
    return <div>
        // Some stuff is rendered based on data
        <Form/>
    </div>

}

The problem I’m having is that every time I add url search params, the page calls getData(), causing unnecessary fetching. Is there a way to add search params without causing data to refetch?

I know that, most of the time, you would want data to refetch when the search params change, but I don’t in this scenario.

I’ve tried turning the page into a client component instead, which works to call getData() only once, but that doesn’t seem to allow me to add metadata to the page. I’ve also seen people say that pages should be server components as much as possible.

Edit:
I think I’ve got it. I just needed to wrap all of my page content inside a client component and do all my fetching there.

// Inner.tsx
"use client"
export default function Inner(){
    const [data, setData] = useState()

    useEffect(() => {
        getData().then(res => setData(res))
    }, [])

    return <div>
        //content rendered here
        <Form/>
    </div>
}

// page.tsx
export default function Page(){
    return <Inner/>
}

2

Answers


  1. Chosen as BEST ANSWER

    I decided to wrap all the contents inside an inner client component instead and do all my fetching there. This seems to work and the data only fetches once now.

    // Inner.tsx
    "use client"
    export default function Inner(){
        const [data, setData] = useState()
    
        useEffect(() => {
            getData().then(res => setData(res))
        }, [])
    
        return <div>
            //content rendered here
            <Form/>
        </div>
    }
    
    // page.tsx
    export default function Page(){
        return <Inner/>
    }
    

  2. I want to store the values of the form in the url so they can persist even if you accidentally refresh the page

    You can try to store in Localstorage

    every time I add url search params, the page calls getData(), causing unnecessary fetching

    It’s because, of useEffect’s dependencies which executes, router.replace().

     useEffect(() => {
            const newSearchParams = new UrlSearchParams({ content })
            router.replace(pathname + "?" + newSearchParams.toString(), { scroll: false })
        }, [content, pathname, router])
    

    I’ve tried turning the page into a client component instead, which works to call getData() only once,….
    I’ve also seen people say that pages should be server components as much as possible.

    • You may also use autocomplete="on" in form tag, so that browser can
      help in quick form filling.
    • Pages should be server-side because they help in metadata generation,
      server-side data fetching etc.

    Solution :

    • Keep page server-side & import that form component (this is a client side component, at top use "use client") in page. In
      local storage store the form state, by making a object . Ex. form:{field1 : value1,field2 : value2}. localStorage key = form, value = Object.

    • In useEffect, check if form key exists, if exists then get it from localstorage and parse values & set them as default values in form fields, else if it doesn’t exists just keep them empty.

    Please Read :

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