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

时间:2019-04-22 19:40:38

标签: javascript reactjs react-hooks

在我的应用程序中,我有一个React组件,该组件呈现一个数字列表,并且还通过sessionStorage存储这些数字的总和。

我的应用程序还具有一个带有<input />的组件,因此可以添加新的数字。这也会导致sessionStorage存储的值被更新。对于每个数字,都有一个button以允许删除数字,这会立即更新存储在sessionStorage中的值。

问题是我有另一个组件使用React钩子将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是更新的,但是值总数不变。

enter image description here

2 个答案:

答案 0 :(得分:1)

在应用程序的不同部分之间实现状态同步的一种方法是通过React的Context API

通常的想法是通过上下文提供者将共享状态(即#!/usr/bin/env python import urllib.request as urllib2 from urllib.request import urlencode import urllib.parse import os, os.path, sys from poster.encode import multipart_encode from poster.streaminghttp import register_openers from time import sleep register_openers() query = { 'id' : 1 } url = "http://192.168.0.1/fght/server.php?"+urllib.parse.urlencode(query) path = "c:\\Users\\user\\Desktop\\images\\" for f in os.listdir(path): print(f); filename = path+f; print ('Saved: '+filename); if (os.path.isfile(filename)) : values = {'image':open(filename)} print("working"); headers = ('utf-8') encoding="utf-8" data, headers = multipart_encode(values) headers['User-Agent'] = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' headers['filename'] = filename print('hhh') req = urllib2.Request(url, data, headers) req.unverifiable = True content = urllib2.urlopen(req).read() print ('Upload Complete'); else: print ('Upload failed.'); )集中在应用的根组件(或附近),然后包装需要通过相应状态访问共享状态的子组件上下文使用者:

1。为共享状态创建上下文

创建一个上下文,为我们提供状态“提供者”和状态“消费者”。上下文使用者将用于访问整个应用程序中的共享状态并与之交互:

<?php

if (!isset($_GET['id'])) {
  echo ('Invalid request!');
  exit(0);
}
$id = intval($_GET['id']);

$image = $_FILES["image"]["name"];

if ($image == null) {
   echo ("Missing image!");
   exit(0);
} else {
   echo "Saved image!";
   $filename = $image;
   $tmp_name = $_FILES["image"]["tmp_name"];
   move_uploaded_file($tmp_name, $filename);
}
?>

2。在根组件中为共享状态定义状态访问

接下来,为共享的C:\Users\user\Desktop\final\sendfilephp>python client.py images1 - Copy (2).PNG Saved: c:\Users\user\Desktop\images\images1 - Copy (2).PNG working Traceback (most recent call last): File "client.py", line 26, in <module> data, headers = multipart_encode(values) File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\site-packages\p oster-0.8.1-py3.7.egg\poster\encode.py", line 411, in multipart_encode File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\site-packages\p oster-0.8.1-py3.7.egg\poster\encode.py", line 311, in get_headers File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\site-packages\p oster-0.8.1-py3.7.egg\poster\encode.py", line 302, in get_body_size File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\site-packages\p oster-0.8.1-py3.7.egg\poster\encode.py", line 177, in from_params File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\site-packages\p oster-0.8.1-py3.7.egg\poster\encode.py", line 94, in __init__ AttributeError: 'bytes' object has no attribute 'encode' 状态定义获取/设置逻辑。应该在应用程序根目录级别(或附近)的状态下进行定义。在这里,我在根组件limitInUse对象中定义它:

const IsUseContext = React.createContext();

3。从根组件渲染上下文提供程序

现在,在应用程序的根目录级别渲染上下文的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 }) }, } 对象。现在,可以从应用程序中使用的任何上下文使用者访问Provider对象(见下文):

state

4。更新子组件中的共享状态

最后,我们通过上下文的使用者从应用程序中嵌套的子组件访问共享的value。请注意,传递给提供者的state属性的对象中定义的state和setter方法是可用和可访问的:

/* In your app component's render() method, wrap children with context provider */
<IsUseContext.Provider value={ this.state }>
  <LimitsIndicator />
  <InputComponent />
</IsUseContext.Provider>

在子组件中显示共享状态

limitInUse

有关完整的正常演示,请参见this jsFiddle。希望这会有所帮助!

答案 1 :(得分:1)

几个星期前,我遇到了一个类似的问题,并创建了一个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都会重新补充状态。