ReactJS:如何在组件之间同步 sessionStorage 状态
ReactJS: How to synchronize sessionStorage state between components
在我的应用程序中,我有一个呈现数字列表的 React 组件,它还通过 sessionStorage
存储这些数字的总和。
我的应用程序还有一个带有 <input />
的组件,以便可以添加新号码。这也会导致 sessionStorage
存储的值被更新。对于每个数字,存在一个 button
以允许删除数字,这会立即更新存储在 sessionStorage
.
中的值
问题是我有另一个组件使用存储在 sessionStorage
中的值作为使用反应挂钩的状态,但是当我更新 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.为共享状态创建上下文
创建一个上下文,为我们提供一个状态 "provider" 和一个状态 "consumer"。上下文使用者将用于访问整个应用程序中的共享状态并与之交互:
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
组件,并通过提供者的 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
道具的对象中定义的状态和 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 程序包来做到这一点:通过上下文 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。通过上下文注入状态:
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
重新水化。
在我的应用程序中,我有一个呈现数字列表的 React 组件,它还通过 sessionStorage
存储这些数字的总和。
我的应用程序还有一个带有 <input />
的组件,以便可以添加新号码。这也会导致 sessionStorage
存储的值被更新。对于每个数字,存在一个 button
以允许删除数字,这会立即更新存储在 sessionStorage
.
问题是我有另一个组件使用存储在 sessionStorage
中的值作为使用反应挂钩的状态,但是当我更新 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.为共享状态创建上下文
创建一个上下文,为我们提供一个状态 "provider" 和一个状态 "consumer"。上下文使用者将用于访问整个应用程序中的共享状态并与之交互:
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
组件,并通过提供者的 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
道具的对象中定义的状态和 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 程序包来做到这一点:通过上下文 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。通过上下文注入状态:
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
重新水化。