【问题标题】:How to update state using LocalStorage in ReactJS如何在 ReactJS 中使用 LocalStorage 更新状态
【发布时间】:2019-08-14 08:37:41
【问题描述】:

我有一个数组,每次调用 componentDidMount() 时都会获取 API 数据。我有一个默认布尔值为 true 的对象推送到数组中的每个元素。设置了一个 onClick 函数,当点击特定元素时,它的布尔值变为 false 并且数组被放置在 localStorage 中。

我需要数据数组在每次重新加载页面时不断刷新,所以我检查了我的 componentDidMount() 方法,该方法只接收来自我刚刚保存在 localStorage 中的数组的布尔值。

虽然这可行,但布尔值是基于索引而不是元素本身分配的。这里的问题是,如果位置 2 中的元素“A”最初设置为 false,然后在另一个 API 调用之后与位置 3 中的元素“B”交换,那么布尔值将不正确,因为“B”现在将为假,“A”现在为真。

import React from 'react';
import StarBorder from '@material-ui/icons/StarBorder';
import Star from '@material-ui/icons/Star';
import axios from 'axios';

class Test extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
          data: [],
        }
    }

    componentDidMount() {

            axios.get('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=true')
            .then(res => {
                const data = res.data;

                const fromLocalStorage = localStorage.getItem('test');

                if (localStorage.getItem('test')) {
                  const dataFromLocalStorage = JSON.parse(fromLocalStorage);
                  this.setState({ data: data.map((x, i) => ({...x, starIcon: dataFromLocalStorage[i].starIcon }))})
                } else {
                 this.setState({ data: data.map(x => ({...x, starIcon: true}))})
                }

            }) 
    }

    handleClick = (n) => {

        this.setState(prevState => ({
          data: prevState.data.map((x) => (x === n ? {
            ...x,
            starIcon: !x.starIcon
          } : x))
        })
        , () => {
          localStorage.setItem('test', JSON.stringify(this.state.data));
        });

      }

    render() {
        return (
        <div>
            <table border="1">
                <thead>
                    <tr>
                    <td>Rank</td>
                    <td>Icon</td>
                    <td>Name</td>
                    <td>Price</td>
                    </tr>
                </thead>
                <tbody>
                {this.state.data.map((n, i) => {
                    return (
                        <tr>
                        <td>{n.market_cap_rank}</td>
                        <td> <span onClick={() => this.handleClick(n)}> {n.starIcon ? <StarBorder/> : <Star /> } </span> </td>
                        <td>{n.name}</td>
                        <td>{n.current_price}</td>
                        </tr>
                    );
                    })}
                </tbody>
            </table>
        </div>
        );
    }
}

export default Test;

代码沙盒链接https://codesandbox.io/s/shy-fog-7yplb

如果您要更改例如位置 40 中名为“Algorand”的项目,请单击 true 到 false,这将按预期工作。然而,API 调用会刷新其余数据,“Algorand”可能不再位于第 40 位,但第 40 位的布尔值仍然为 false,并且不会映射到“Algorand”

【问题讨论】:

  • 您能为此创建一个工作示例吗?
  • 你要我链接一个codeandbox吗?
  • 是的,codeandbox 可以工作。
  • 给元素一个键(即 n.name)然后将它传递给 handleClick() 以存储值?
  • 您正在检查 x === n 哪些是对象。试试 x.id === n.id 虽然我总是发现没有 40 是 Algorand。也许您可以在订单更改时检查更改是否有效。

标签: javascript reactjs local-storage


【解决方案1】:

尝试在你的 componentDidMount 中使用它

const fromLocalStorage = localStorage.getItem("test");

if (localStorage.getItem("test")) {
          const dataFromLocalStorage = JSON.parse(fromLocalStorage);
          let updatedData = data.map((d) => {

            const result = dataFromLocalStorage.find( dfls => dfls.id === d.id );
            return {...d, starIcon: result.starIcon} ;
          })
          this.setState({
            data: updatedData
          });
        } else {
          this.setState({ data: data.map(x => ({ ...x, starIcon: true })) });
        }

我在这里所做的是当您在您的状态中映射刷新的数据时,我没有匹配整个对象(这不会正确工作),而是从数组中找到正确的对象并使用它的 startIcon。

【讨论】:

  • 如果唯一的依赖值是您的 startIcon,您可以只添加 id(如果它是您的唯一标识符)和 starIcon 值。在本地存储中存储具有如此多数据的整个对象是没有意义的。
  • 我只会存储我标记为假(或更改)的对象。因此,如果 .find 的结果未找到,我将直接添加该对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-05
  • 1970-01-01
  • 2017-07-16
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
相关资源
最近更新 更多