polemius/recoil-persist

How rehydration works?

josoroma-zz opened this issue · 8 comments

Hi hackers!

I was wondering... what is this the right way to rehydrate the state?

My current version is:

state/user/atom.ts

import { atom } from "recoil";

import StateUser from "state/user/types";
import { statePersist } from "config/constants";

const ATOM_KEY = "user";

const userDefault: StateUser = {
  email: "",
  firstName: "",
  id: "0",
  lastName: "",
  token: "",
};

/**
 * Get the localStorage persisted state, then rehydrate the atom.
 */
const userPersistedStorage = window.localStorage.getItem(statePersist.key);

const userPersisted = userPersistedStorage
  ? JSON.parse(userPersistedStorage)[ATOM_KEY]
  : userDefault;

/**
 * User State - Create or Rehydrate the Atom.
 */
const userAtom = atom({
  key: ATOM_KEY,
  default: userPersisted,
  // @ts-ignore
  persistence_UNSTABLE: {
    type: ATOM_KEY,
  },
});

export default userAtom;

index.tsx

import React, { StrictMode } from "react";
import ReactDOM from "react-dom";
import { RecoilRoot } from "recoil";
import recoilPersist from "recoil-persist";

import { statePersist } from "config/constants";

import "./index.css";
import App from "./App";

const { RecoilPersist, updateState } = recoilPersist(
  statePersist.atomsToPersist,
  {
    key: statePersist.key,
    storage: localStorage,
  }
);

ReactDOM.render(
  <StrictMode>
    <RecoilRoot initializeState={updateState}>
      <RecoilPersist />
      <App />
    </RecoilRoot>
  </StrictMode>,
  document.getElementById("root")
);

Do recoil-persist offers state rehydration?

@josoroma Hi, yes, recoil-persist offers state rehydration. But I am not sure what this lines are doing in your code?

const userPersistedStorage = window.localStorage.getItem(statePersist.key);

const userPersisted = userPersistedStorage
  ? JSON.parse(userPersistedStorage)[ATOM_KEY]
  : userDefault;

recoil-persist should rehydrate the state.
The default value could be userDefault.
Please take a look in examples in README.md

Thanks a bunch @polemius !

I tried: https://github.com/polemius/recoil-persist#usage

const { RecoilPersist, updateState } = recoilPersist(
    statePersist.atomsToMantain, // ['user']
    {
        key: statePersist.key,
        storage: localStorage
    }
)

but this part is never rehydrating the user state (once I refresh the browser the localstorage data exist but the rehydration is being ignored):

   <RecoilRoot initializeState={({set}) => {
       updateState({set})
    }>
      <RecoilPersist />
      <App />
    </RecoilRoot>

Not sure what I am not doing right!

Thanks!

@polemius those lines are just getting the whole state from the localStorage, then it get the user slice only. So if the data exists in localStorage it will rehydrate this data on any browser reload, if not, it will use the default values. So to me, this hack is making the rehydration part work.

@josoroma This is strange that rehydration doesn't work. Try remove any properties from recoilPersist function. Then it should store everything.

const { RecoilPersist, updateState } = recoilPersist()

<RecoilRoot initializeState={({set}) => updateState({set})>
   <RecoilPersist />
   <App />
</RecoilRoot>

Also try check the localstorage in your browser.

Are you updating the atom values? Because recoil-persist will save data only if the atom will change (limitation of recoil library).

@josoroma I have ran your project locally and found that function set from RecoilRoot doesn't work to setting the value for your atom. If I am trying use set directly like this:

ReactDOM.render(
  <StrictMode>
    <RecoilRoot
      initializeState={({ set }) => {
        // set({ key: "user" }, { email: "test" });
        updateState({ set });
      }}
    >
      <RecoilPersist />
      <App />
    </RecoilRoot>
  </StrictMode>,
  document.getElementById("root")
);

I am getting error Error: Missing definition for RecoilValue: "user""

I have checked and looks like Recoil doesn't see the atoms if it is not in app tree. You are using lazy loading for each module so user atom not in the app tree.

I have changed the App.tsx to getting the value from atom:

const App: FC = () => {
  const value = useRecoilValue(userAtom);
  return (
    <>
      <CssBaseline />
      <Routes history={history} />
    </>
  );
};

Also I set in user atom default value to default: userDefault. To prevent loading from localstorage with your mechanism.

And suddenly everything works as expected.
I have created the PR with my changes. Please take a look: mismoteam/reacter#1

sweet!!! thank you @polemius

100%