Search code examples
reactjsrecoiljs

Programmatically observing changes in Recoil with React


I'm using Recoil (recoiljs.org) in my react project.

I have a fairly classic setup with a list of items - the object graph looks something like this:

Routes - routes is an array of Route objects
- Route - route object is edited in a form

I use an atom to represent the currently selected Routes array, e.g.

const [routes, setRoutes] = useRecoilValue(currentRoutesViewState);

And I also use a selectorFamily to allow individual controls to bind to and update the state of an individual item.

const routeSelectorFamily = selectorFamily({
  key: "routeSelectorFamily",
  get:
    (routeKey) =>
    ({ get }) => {
      const routes = get(currentRoutesViewState);
      return routes.find((r) => r.key === routeKey);
    },
  set:
    (routeKey) =>
    ({ set }, newValue) => {
      set(currentRoutesViewState, (oldRoutes) => {
        const index = oldRoutes.findIndex((r) => r.key === routeKey);
        const newRoutes = replaceItemAtIndex(
          oldRoutes,
          index,
          newValue as RouteViewModel
        );
        return newRoutes;
      });
    },
});

As you can see, the set function allows someone to update an individual route state and that is replicated up into anything rendering routes.

However, I would like to auto-save any changes to this whole graph but don't know how to easily observe any changes to the Routes parent object. Is there a way to programmatically subscribe to updates so I can serialize and save this state?


Solution

  • You can just use a useEffect for that:

    const currentState = useRecoilValue(currentRoutesViewState);
    
    useEffect(() => {
      // currentState changed.
      // save the current state
    }, [currentState])