在上下文中反应传递缓存和获取/设置功能

时间:2019-10-26 10:02:38

标签: reactjs react-context

我似乎无法使以下代码正常工作。尝试在响应中使用一些简单的“缓存”,我希望使用上下文将其从App组件中传递出去。 App中的状态如下:

  const [cacheData, setCacheData] = useState({});
  const getCache = (key) => {
    console.log('Getting value from cache with key ' + key, cacheData);
    return cacheData[key];
  }
  const setCache = (key, data) => {
    try{
      console.log(cacheData);

      console.log('Setting value to cache with key ' + key, data);
      let dataCopy = JSON.parse(JSON.stringify(cacheData));
      dataCopy[key] = data;
      console.log(dataCopy, cacheData);
      setCacheData(dataCopy); 
      console.log('jaja');
    }catch(err){
      console.log(err);
    }
  }

然后将其传递给上下文,如下所示:

<CacheContext.Provider value={{data: cacheData, get: getCache, set: setCache}}>

在子组件中,我使用cache.get和cache.set,它们都具有正确的console.logs,但是缓存始终是未定义的。缓存数据始终为{}。我的猜测是setCache函数没有做任何事情。

先谢谢大家。另外,如果您认为我正在重新发明轮子,请给我一些帮助:)找不到任何可以帮助我的软件包。

代码段:(从答案中复制,此代码有效。将添加错误代码)

const {useState, useContext, createContext} = React

const fn = () => undefined
const CacheContext = createContext({data: {}, get: fn, set: fn})

const App = () => {
  const [cacheData, setCacheData] = useState({});
  const getCache = (key) => {
    console.log('Getting value from cache with key ' + key, cacheData);
    return cacheData[key];
  }
  const setCache = (key, data) => {
    try{
      console.log(cacheData);

      console.log('Setting value to cache with key ' + key, data);
      let dataCopy = JSON.parse(JSON.stringify(cacheData));
      dataCopy[key] = data;
      console.log(dataCopy, cacheData);
      setCacheData(dataCopy); 
      console.log('jaja');
    }catch(err){
      console.log(err);
    }
  }
  
  return (
    <CacheContext.Provider value={{data: cacheData, get: getCache, set: setCache}}>
      <Main />
    </CacheContext.Provider>
  )
}

const useCache = () => useContext(CacheContext)

const Main = () => {
  const cache = useCache()
  const [key, setKey] = useState('key')
  const [value, setValue] = useState('value')
  
  return (
    <div>
      <input value={key} onChange={(e) => setKey(e.target.value)} /> :
      <input value={value} onChange={(e) => setValue(e.target.value)} />
      <button onClick={() => cache.set(key, value)}>Set</button>
      <div>Existing keys: [{Object.keys(cache.data).join(', ')}]</div>
      <div>Current value of '{key}': {cache.get(key) || 'undefined'}</div>
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

2 个答案:

答案 0 :(得分:0)

为什么不使用LocalStorage或SessionStorage(特定于选项卡)?只需从localStorage推送并获取,您就可以成为好人。或者使用redux-store和redux-persist来处理刷新。

redux:https://www.npmjs.com/package/react-redux

redux-persist:用于将redux存储的数据存储到localStorage的插件:https://www.npmjs.com/package/redux-persist

答案 1 :(得分:0)

问题中的代码按以下方式使用时效果很好。请通过在问题中包括以下代码段并对其进行编辑,直到重现问题,create a Minimal, Reproducible Example {}:

const {useState, useContext, createContext} = React

const fn = () => undefined
const CacheContext = createContext({data: {}, get: fn, set: fn})

const App = () => {
  const [cacheData, setCacheData] = useState({});
  const getCache = (key) => {
    console.log('Getting value from cache with key ' + key, cacheData);
    return cacheData[key];
  }
  const setCache = (key, data) => {
    try{
      console.log(cacheData);

      console.log('Setting value to cache with key ' + key, data);
      let dataCopy = JSON.parse(JSON.stringify(cacheData));
      dataCopy[key] = data;
      console.log(dataCopy, cacheData);
      setCacheData(dataCopy); 
      console.log('jaja');
    }catch(err){
      console.log(err);
    }
  }
  
  return (
    <CacheContext.Provider value={{data: cacheData, get: getCache, set: setCache}}>
      <Main />
    </CacheContext.Provider>
  )
}

const Main = () => {
  const {data, get, set} = useContext(CacheContext)
  const [key, setKey] = useState('key')
  const [value, setValue] = useState('value')
  
  return (
    <div>
      <input value={key} onChange={(e) => setKey(e.target.value)} />
      :
      <input value={value} onChange={(e) => setValue(e.target.value)} />
      <button onClick={() => set(key, value)}>Set</button>
      <div>Existing keys: [{Object.keys(data).join(', ')}]</div>
      <div>Current value of '{key}': {get(key) || 'undefined'}</div>
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

话虽如此,functional updates可以在the new state is computed using the previous state时使用。而且,如果您发现需要命令性代码,异步操作,使用闭包和/或针对性能进行优化的代码的可变引用,则可以使用useRef访问data的未来值:

const {useState, useContext, useRef, createContext, memo} = React

const fn = () => undefined
const CacheContext = createContext({data: {}, get: fn, set: fn})

const App = memo(() => {
  const [cacheData, setCacheData] = useState({});
  const dataRef = useRef();
  dataRef.current = cacheData;
  const getCache = (key) => {
    console.log('Getting value from cache with key ' + key, cacheData);
    return cacheData[key];
  }
  const setCache = (key, data) => {
    try{
      console.log(cacheData);

      console.log('Setting value to cache with key ' + key, data);
      setCacheData(current => {
        const dataCopy = JSON.parse(JSON.stringify(current));
        dataCopy[key] = data;
        return dataCopy;
      })
      setCacheData(dataCopy); 
      console.log('jaja');
    }catch(err){
      console.log(err);
    }
  }
  
  return (
    <CacheContext.Provider value={{dataRef, get: getCache, set: setCache}}>
      <Main />
    </CacheContext.Provider>
  )
})

const Main = memo(() => {
  const {dataRef, get, set} = useContext(CacheContext)
  const [key, setKey] = useState('key')
  const [value, setValue] = useState('value')
  
  const setAsync = () => {
    set('in progress', key)
    setTimeout(() => {
      set(key, value)
      // notice how mutating a reference will NOT trigger a re-render, unlike using `set`
      // set('in progress', undefined)
      delete dataRef.current['in progress']
    }, 3000)
  }
  
  return (
    <div>
      <input value={key} onChange={(e) => setKey(e.target.value)} />
      :
      <input value={value} onChange={(e) => setValue(e.target.value)} />
      <button onClick={setAsync}>Set</button>
      <div>Existing keys: [{Object.keys(dataRef.current).join(', ')}]</div>
      <div>Current value of '{key}': {get(key) || 'undefined'}</div>
      <div>Current value of 'in progress': {get('in progress') || 'undefined'}</div>
    </div>
  )
})

ReactDOM.render(<App />, document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>