question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

useRecoilState inside custom hooks behaves weirdly

See original GitHub issue

Hi there, im really excited about using Recoil because it will solve many of my scenarios with a minimal implementation 😃

But something that i thought was very intuitive doesn’t work.

I have a global state which is a query composed of key:value pairs, and i need to read this in different places of the app, but the way i update this from data is similar and it’s not as simple as setQuery(string), i need to do some processing to form this string before setting it.

So I thought, I’ll create a custom hook that would get the recoil state and have a function to process the string and then set the new recoil state.

But for some reason when I do setQuery from the RecoilState, it produces updates in an irregular manner.

Inside this custom hook I have a useEffect listening to query changes, but the first time it “reacts” to it, the query value is the previous instead of the new one.

I tried using a useRef for the state to keep it updated somewhere else, but I get the same result.

here’s a code example:

const customHook = () => {
  const [query, setQuery] = useRecoilState(queryState); //string
  const [deserialized, setDeserialized] = useState(); 

  const updateQuery = (key, value) => {
    const newQuery = `${query} ${key}:${value}`
    setQuery(newQuery)
  }

  useEffect(() => {
    const newDeserialized = // logic  to deserialize value using query recoil state, but it's the outdated value so i get wrong results
     setDerserialized(newDeserialized)
  }, [query])

return [deserialized, updateQuery]

Is this just never going to work? Or am doing something wrong here?

Thanks and kind regards

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7

github_iconTop GitHub Comments

3reactions
BenjaBobscommented, Sep 28, 2020

We use browser history from createBrowserHistory() and then store the location in an atom.

export const _location = atom({
  key: '_location',
  default: browserHistory.location,
});

We then mount a synchronization component right beneath our <RecoilRoot>:

export function HistoryRecoilSync() {
  const history = RoutingRepository.history(); // gets the browser history object
  const set = useSetRecoilState(_location);

  useEffect(() => {
    return history.listen((location, action) => {
      // action = 'PUSH' | 'POP' | 'REPLACE';
      set(location);
    });
  }, [history, set]);

  return <></>;
}

It doesn’t render anything, it just listens to history changes.

Then in your toplevel component in which you have the recoil root:

export default function Startup() {
  return (
    <RecoilRoot>
      {/* this component is empty and it's only purpose is to sync external state with Recoil */}
      <HistoryRecoilSync />
      <YourAppComponentHere />
    </RecoilRoot>
  );
}

That way you have the location available in Recoil. 😄

1reaction
Geddardcommented, Sep 28, 2020

That’s smart 😃 I think that my solution will work for now since i only need history in 2 components that are wrapped by this parent, but I’ll bookmark your solution because i think i will need something like this later on.

Thanks for the help!

Read more comments on GitHub >

github_iconTop Results From Across the Web

React Custom Hook function is not reading recoil Atom
I am trying to make a multi-request, multi-step form with formik, typescript and recoil in a react project. I have created a custom...
Read more >
Use recoil in react custom hooks - DEV Community ‍ ‍
One of the biggest limitation is that the useRecoilState and useRecoilValue hook does not work properly in custom hooks.
Read more >
Defining our 2023 architecture for frontend React applications ...
We can create custom hooks following the same conventions, for example, for fetching data(in this example I'm using Axios as a dependency for ......
Read more >
JavaScript - Schneide Blog
E.g. if your custom hook has an internal setState(), think hard about whether you pass that function to the outside via the hook...
Read more >
The new wave of React state management | Hacker News
Put that code in a custom hook, export it and you re-invented Redux. ... And having it behave differently from useState is fine,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found