luisanton-io / recoil-nexus

MIT License
163 stars 13 forks source link

Update atoms whose values are objects without having to get them first #11

Closed HiggsWRX closed 2 years ago

HiggsWRX commented 2 years ago

In recoil, when an atom is an object you can usually set its new state by using the previous notation and rest operator, for example, imagine our atom is

const userAtom = atom({
  key: "userAtom",
  default: {
    authenticated: false,
    role: "cleaner",
  },
});

Whenever we update the value, to save ourselves from having to put the loaded atom value in the useEffect dependencies we can just use the previous notation with destructuring, like so

(beginning of component...)
const setUser = useSetRecoilState(userAtom);

useEffect(() => {
  setUser((previous) => ({ ...previous, authenticated: true });
}, [setUser]);

If we didn't use previous and the spread operator, we would have to also load the user, put it in the useEffect's dependencies, and spread the user object instead, which after updating the user state, in many cases will execute multiple times without necessity and in some cases start an infinite loop.

Would this be possible in recoil-nexus?

something like

setRecoil(userAtom, (previous) => {...previous, authenticated: true});

or even like

setRecoil(userAtom, { ...getRecoil(userAtom), authenticated: true });

Thank you

luisanton-io commented 2 years ago

Hello @HiggsWRX, this is already possible. Here is a working sandbox.

As you can see you can pass a function to setRecoil

const toggleLoading = async () => {
  setRecoil(state, (s) => ({
    // you can spread ...s here,
    counter: s.loading ? s.counter : s.counter + 1,
    loading: !s.loading
  }));
};

L