React Context API - persist data on page refresh
Asked Answered
T

3

75

Let's say we have a context provider set up, along with some initial data property values.

Somewhere along the line, let's say a consumer then modifies those properties.

On page reload, those changes are lost. What is the best way to persist the data so we can retain those data modifications? Any method other than simply local storage?

Torrance answered 23/11, 2018 at 23:29 Comment(1)
Hello, can I know the solution that you followed to persist the context api state?Clientele
S
64

Yeah, if you want the data to persist across reloads, your options are going to be storing that info server-side (via an api call) or in browser storage (local storage, session storage, cookies). The option you'll want to use depends on what level of persistence you're looking to achieve. Regardless of storage choice, it would likely look something along the lines of

const MyContext = React.createContext(defaultValue);

class Parent extends React.Component {
  setValue = (value) => {    
    this.setState({ value });
  }

  state = {
    setValue: this.setValue,
    value: localStorage.getItem("parentValueKey")
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.state.value !== prevState.value) {
      // Whatever storage mechanism you end up deciding to use.
      localStorage.setItem("parentValueKey", this.state.value)
    }
  }

  render() {
    return (
      <MyContext.Provider value={this.state}>
        {this.props.children}
      </MyContext.Provider>
    )
  }
}
Schwa answered 24/11, 2018 at 5:28 Comment(1)
I would also like to see this with a ProviderHylan
M
14

Context doesn't persist in the way you want. Here's a sample of what I've done, using stateless functional with React hooks.

import React,  {useState, useEffect} from 'react'

export function sample(){
  // useState React hook
  const [data, setData] = useState({})
  const [moreData, setMoreData] = useState([])

  // useState React hook
  useEffect(() => { 
    setData({test: "sample", user: "some person"})
    setMoreData(["test", "string"])
  }, [])

  return data, moreData
}

export const AppContext = React.createContext()

export const AppProvider = props => (
  <AppContext.Provider value={{ ...sample() }}>
    {props.children}
  </AppContext.Provider>
)

Understand from the start that this isa workaround, not a permanent solution. Persisting data is the job of a database, not the client. However, if you need persisted data for development, this is one way. Notice first that I'm using React hooks. This is a fully supported feature as of 16.8. The useEffect() replaces the lifecycle methods found in class declarations like that of TLadd above. He's using componentDidUpdate to persist. The most up-to-date way of doing this is useEffect. When the app is refreshed this method will be called and set some hard-coded data in context.

To use the provider:

import React from 'react'
import Component from './path/to/component'
import { AppProvider } from './path/to/context'

const App = () => {
  return (
    <AppProvider>
      <Component />
    </AppProvider>
  )
}

When you refresh, data and moreData will still have whatever default values you assign to them.

Masuria answered 24/3, 2019 at 21:45 Comment(3)
Just to note it's React.createContext not React.CreateContextIchnite
This have not worked for me. The approach, a little different that worked can be found here - the article from Alex Krush.Flagellant
This only works if the data is static. But if you need data retreived from an API to persist in storage or for user changed data, which is what I understand is being asked, it doesn't work...Endocrine
C
1

I am assuming that you are already familiar with setting context and setting up the context provider.

One of the things you can do is to store the value in the browser's Cookie or any storage available to you, and then, in your Context Provider, retrieve the value, if you can find it, you set it, if not, set the default. If the provider file is a class based component, you would like to retrieve this value in the constructor(), otherwise if it is functional, you can use useLayoutEffect() to set it.

Combatant answered 22/1, 2022 at 6:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.