#useSearchParams and state sync

1 messages · Page 1 of 1 (latest)

cobalt meadow
#
const [searchParams, setSearchParams] = useSearchParams({ key: '' })
const [value, setValue] = useState('')
const handleSearch = async () => {
        setIsLoading(true)
        try {
           response = axios.post(...)
        } catch (error) {
           setError(error)
        }
        setIsLoading(false)
    }


    function submitUrlParams() {
        handleSearch()
    }

    function submitForm() {
        handleSearch()
        setSearchParams({ key: value })
    }

    useEffect(() => {
        const searchParamValue = searchParams.get('key')
        if (searchParamValue) {
            setValue(searchParamValue)
            submitUrlParams()
        }
    }, [])

I want to submit the form then update the url to match the submit input values.
I also want to use the key value in the url so that when I go to the url, it automatically submits the form with the value of the key. I'm having trouble with useSearchParams. It when going to the url with key: value, the submission value is an empty string.

Is there a better way to achieve my goal? I researched that its good to use a single source of truth...

cobalt meadow
#

the axios request uses the state 'value' to get the data... I think its because im setting the state then running the handleSearch function which takes the state ... which is empty...

#

or ""

#

but how can I get around this?

peak kernel
#

Do you use the loader API of react router?

cobalt meadow
#

I don't

peak kernel
#
try {
  response = axios.post(...)
}
#

i have no idea where this variable is

#

but basically you can just make a fetch when the search params changed

#

then revalidate

#

if you don't use the loader API, setSearchParams won't tell anyone that it's has changed, only the URL state changed i guess

#

i have a simple hook which can use to fetch when the keyed data change

import { useCallback, useEffect, useState } from "react";

const Cache = new Map();

export function useFetch<T, E = any>(
  fetchFn: () => Promise<T>,
  cacheKey?: string,
  keyed?: any
) {
  const [data, setData] = useState<T>(Cache.get(cacheKey));
  const [error, setError] = useState<E>();
  const clearCache = useCallback(() => {
    Cache.delete(cacheKey);
  }, [cacheKey]);
  const flush = () => Cache.clear();
  useEffect(() => {
    if (data && cacheKey) Cache.set(cacheKey, data);
  }, [cacheKey, data]);

  useEffect(() => {
    if (!data) fetchFn().then(setData).catch(setError);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [keyed]);

  return [data, { error, clearCache, flush }] as const;
}

you can add the loading state as well if you need

#

but if you use the loader API then it's way simpler
just call setSearchParams, then everything is automatically revalidated

cobalt meadow
#

Very interesting.

#

I'll have to give it a go

cobalt meadow
#

Thanks. I'm going to try and upgrade to loader api since I'm currently on react-router 6.3

chrome egret
# cobalt meadow Thanks. I'm going to try and upgrade to loader api since I'm currently on react-...

Loader api is definitely simpler imo, but if you wanted to specifically accomplish it the way you were trying, the answer would be a useEffect that listens for the state change and runs the fetch again from axios. This lets react finish batching the update then sees a fresh value and runs the axios request. The other option would be to not send the request using the state variable but just directly use the data you were using to update the state variable.

Hopefully that helps clear some things up, but maybe I misunderstood your question

cobalt meadow
#

I wound up using the data from the query params to update the state variables through a useEffect and also fetching the data.

cobalt meadow
#

Upon more research I'm realising its a huge topic that isn't well standardized. Migrating from 6.3 to latest version and to use RouteProvider is a task in itself so I don't think I can add loader api easily. I'm sticking to useSearchParam and useEffect at the moment but I really want to try the loader apis in my free time IF I have some.

#

***This topic includes mixing routing and form state and browser apis...
So what do you guys think?