在我的应用程序中,我有一个React组件,它呈现一个数字列表,它还通过sessionStorage
存储这些数字的总和。
我的应用程序还有一个带有<input />
的组件,以便可以添加新的数字。这也会导致sessionStorage
存储的值被更新。对于每个数字,存在button
以允许删除数字,并且这会立即更新存储在sessionStorage
中的值。
问题是我有另一个组件使用存储在sessionStorage
中的值作为使用react钩子的状态,但是当我更新sessionStorage
中的值时,state的值不会改变。
我正在尝试使用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
状态定义get / set逻辑。这应该在应用程序根级别(或附近)的状态下定义。在这里,我在根组件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
组件,并通过提供程序的state
prop传递value
对象。现在可以从应用程序中使用的任何上下文使用者访问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>)
有关完整的演示,请参阅this 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
重新水化。