繁体   English   中英

ReactJS:如何在组件之间同步 sessionStorage 状态

[英]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. 随心所欲地使用它。 每次更改都会触发 ReactlocalStorage更新,这正是您想要的。 无论如何,您的 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM