[英]ReactJS: How to synchronize sessionStorage state between components
在我的应用程序中,我有一个 React 组件,它呈现一个数字列表,它还通过sessionStorage
存储这些数字的总和。
我的应用程序还有一个带有<input />
的组件,以便可以添加新数字。 这也会导致sessionStorage
存储的值被更新。 对于每个数字,都有一个button
可以删除数字,这会立即更新sessionStorage
存储的值。
问题是我有另一个组件使用存储在sessionStorage
的值作为使用 react 钩子的状态,但是当我更新sessionStorage
的值时,状态的值不会改变。
我正在尝试使用useEffect()
使其更新,但它不起作用:
import React from 'react';
import { useState, useEffect } from "react";
const LimitsIndicator = props => {
const {
limits: { total, used },
currency,
t,
type,
} = props;
const [limitInUse, setInUse] = useState(sessionStorage.getItem('inUse'));
useEffect(() => {
setInUse(sessionStorage.getItem('inUse'))
})
return (
<div>{limitInUse}</div>
)
}
在这张图片中,它显示了总和:250,以及两个值:100 和 150,但是值 150 被取消了,正如您在控制台中看到的, sessionStorage
是更新的,但总和的值没有改变.
在应用程序的不同部分之间实现状态同步的一种方法是通过 React 的Context API 。
一般的想法是通过上下文提供程序将共享状态(即limitInUse
)集中在(或附近)应用程序的根组件处,然后通过相应的上下文使用者包装需要访问共享状态的子组件:
1. 为共享状态创建上下文
创建一个上下文,为我们提供一个状态“提供者”和一个状态“消费者”。 上下文使用者将用于访问整个应用程序中的共享状态并与之交互:
const IsUseContext = React.createContext();
2.在根组件中定义共享状态的状态访问
接下来,为共享的limitInUse
状态定义获取/设置逻辑。 这应该在您的应用程序的根级别(或附近)的状态中定义。 在这里,我在根组件state
对象中定义了它:
this.state = {
/* Define initial value for shared limitInUse state */
limitInUse : sessionStorage.getItem('inUse'),
/* Define setter method by which limitInUse state is updated */
setLimitInUse: (inUse) => {
/* Persist data to session storage, and update state to trigger re-render */
sessionStorage.setItem('inUse', `${ inUse }`)
this.setState({ limitInUse })
},
}
3. 从根组件渲染上下文提供者
现在,在您的应用程序的根级别呈现上下文的Provider
组件,并通过提供程序的value
属性传递state
对象。 现在可以从应用程序中使用的任何上下文使用者访问state
对象(见下文):
/* In your app component's render() method, wrap children with context provider */
<IsUseContext.Provider value={ this.state }>
<LimitsIndicator />
<InputComponent />
</IsUseContext.Provider>
4. 更新子组件中的共享状态
最后,我们通过上下文的使用者从应用程序中的嵌套子组件访问共享的limitInUse
。 请注意,传递给提供者的value
prop 的对象中定义的 state 和 setter 方法是可用且可访问的:
/* Update shared limitInUse state via context consumer */
return (<IsUseContext.Consumer>
{ ({ setLimitInUse }) => <input onChange={
(event) => setLimitInUse(event.currentTarget.value) } />
}
</IsUseContext.Consumer>)
在子组件中显示共享状态
/* Access shared limitInUse via context consumer */
return (<IsUseContext.Consumer>
{ ({ limitInUse }) => (<div> {limitInUse} </div>) }
</IsUseContext.Consumer>)
有关完整的工作演示,请参阅此 jsFiddle 。 希望这可以帮助!
几周前,我遇到了一个类似的问题,并创建了一个 NPM 包来做到这一点:通过 Context API 在组件之间共享状态,并自动将它持久化到localStorage
。 看看并尝试一下:它被称为repersist 。
例子。
1. 首先在配置文件中定义共享的持久化状态:
import repersist from 'repersist'
const { Provider, useStore } = repersist({
storageKey: 'mystorekey',
init: {
counter: 0,
search: ''
},
actions: {
increment: () => ({ counter}) => ({
counter: counter + 1
}),
typeSearch: search => ({ search })
}
})
export { Provider, useStore }
2. 通过 Context 注入状态:
import { Provider } from './storeConfig'
ReactDOM.render(
<Provider>
<App/>
</Provider>,
document.getElementById('root')
)
3. 随心所欲地使用它。 每次更改都会触发 React和localStorage
更新,这正是您想要的。 无论如何,您的 localStorage 基本上是同步的。
import { useStore } from './storeConfig'
const SearchField = () => {
const [{ search }, { typeSearch }] = useStore()
return (
<input value={search} onChange={e => typeSearch(e.target.value)}/>
)
}
每次您的页面刷新时,状态都会被localStorage
重新水化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.