reactjstypescriptjotai

How to make a "local atom" availble in the whole child component tree?


Learning how to use Jotai state management, I'm facing an issue regarding the propagation of atoms through part of the component tree.

Let's imagine I have this component tree (each node is a React component):

Declaring "global" atoms (like current logged user, selected theme, ...) is straightforward. I can write in a module these atoms and provide them directly to the use useAtom hook.

However, I have some large part of the application that can share local data.

For example, I need to load data for each customer, and make this data available in the component sub tree of every customer component. Obviously, this data is different for each customer tree.

To make this data available, I can see several solutions:

  1. create an atom inside the Customer component and pass the atom by props in every nested component. Because the project uses typescript, it should force to declare the atom in every props type of every component inside the tree (props drilling)
  2. create an atom family (globally). Inside the CustomerComponent, generate an Id (or use the data of the customer) and set the customer data. Pass the customer ID as props for the whole component tree (props drilling again) and let each component call the useAtom hook by passing the atomFamily and customer ID parameter
  3. use the same solution as above, but use a classic react Context to provide the customer ID to the whole substree. Because the customerID is readonly for the tree, I think it's ok to use context here, no complete rerender should occur

I also was wondering if there's something I can do by playing with local Provider (inserting a Provider component around the Customer component), but this way, as far as I know, I will "loose" my global atoms, or to be precise, each global atoms will hold different values inside every Provider.

To conclude, the question is: what is the recommended way to deal with atom propagation when value is shared only in part of the component tree?


Solution

  • Jotai Scopes explicitly deals with this use case, allowing multiple stores that can override the parent store's atoms.

    Another choice is to simply use a regular React Context provider to pass down a component-created atom (in case you want contextual state to also be mutable without inefficient re-renders).

    const AtomContext = createContext(undefined);
    
    function MyScopedAtom(props) {
      const someAtom = useMemo(() => atom(0), []);
      return <AtomContext.Provider value={someAtom} {...props} />;
    }
    
    function MyComponent() {
      const [value, set] = useAtom(useContext(AtomContext));
      ...
    }