Shuzheng
Shuzheng

Reputation: 13830

How do I persist state between re-creations of the same component?

I have created a React application that fetches a list of clusters from a database and displays it in a grid view. Since, the list of clusters changes very rarily (maybe once a week), I don't want to fetch it every time the user visits /clusters.

I have tried to change useState to useRef, but in both cases clusters is [], when the component is re-created (not re-rerendered?)

I'm not sure my terminology is correct, so please correct me, if I'm wrong.

What's the React way of solving this problem?

useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

App.jsx:

...
<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/clusters" element={<ClusterList />} />
  <Route path="/clusters/:id" element={<ClusterInfo />} />
  <Route path="/assets" element={<Assets />} />
</Routes>
...

ClusterList.jsx:

export const ClusterList = () => {
  const discoveryApi = useApi(discoveryApiRef);
  const authFetch = useAuthFetch();

  const [loading, setLoading] = useState<boolean>(false);
  const [clusters, setClusters] = useState<Cluster[]>([]);

  const fetchClusters = useCallback(async (): Promise<Cluster[]> => {
    const url = await discoveryApi.getBaseUrl('containerplatform');
    const response = await authFetch(`${url}/clusters`);
    return await response.json();
  }, [discoveryApi, authFetch]);

  useEffect(() => {
    (async () => {
      try {
        setLoading(true);
        const _clusters = await fetchClusters();
        setClusters(_clusters);
      } finally {
        setLoading(false);
      }
    })();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [fetchClusters]);
...

Upvotes: 0

Views: 31

Answers (1)

Raghav Joshi
Raghav Joshi

Reputation: 143

You can't rely on state variables to persist information, you will need to use localStorage or sessionStorage for storing cluster information, in you case using localStorage will suffice.

Example of using localStorage:-

  const fetchClusters = useCallback(async (): Promise<Cluster[]> => {
    if (!localStorage.getItem('clusters')){
      const url = await discoveryApi.getBaseUrl('containerplatform');
      const response = await authFetch(`${url}/clusters`);
      const clusters = await response.json();
      localStorage.setItem('clusters', JSON.stringify(clusters))
    }

    return JSON.parse(localStorage.getItem('clusters'))
  }, [discoveryApi, authFetch]);

Upvotes: 1

Related Questions