【问题标题】:React: Persisting State Using Local StorageReact:使用本地存储持久化状态
【发布时间】:2023-04-08 12:18:01
【问题描述】:

我正在编写一个应用程序,其中有一组评论,一个人可以回复评论,但每条评论只能有一个回复。到目前为止,我通过在我的 ReviewCardDetails 组件中呈现一个 ReviewResponseBox 组件并将 review_id 作为道具传递来做到这一点。 我已经实现了逻辑,因此一旦有一个 ReviewResponse,将不再出现编写另一个的表单。然而,在我用一个空数组初始化这个组件的状态之前,所以当我刷新我的页面时,响应消失了,表单又回来了。 (现在注释掉了)

我正在尝试通过使用 React LocalStorage 保持我的状态来解决这个问题,但是我在编写我的方法来执行此操作时遇到了麻烦。这是我目前所拥有的:

呈现 ReviewResponseBox 并将 review_id 作为 props 传递的组件:

import React from "react";
import './Review.css';
import { useLocation } from "react-router-dom";
import StarRatings from "react-star-ratings";
import ReviewResponseBox from "../ReviewResponse/ReviewResponseBox";

const ReviewCardDetails = () => {
  const location = useLocation();
  const { review } = location?.state; // ? - optional chaining

  console.log("history location details: ", location);
  return (
    <div key={review.id} className="card-deck">
      <div className="card">
        <div>
        <div className='card-container'>
          <h4 className="card-title">{review.place}</h4>
          <StarRatings
            rating={review.rating}
            starRatedColor="gold"
            starDimension="20px"
          />
          <div className="card-body">{review.content}</div>
          <div className="card-footer">
            {review.author} - {review.published_at}
          </div>
          </div>
        </div>
      </div>
      <br></br>
    <ReviewResponseBox review_id={review.id}/>
    </div>
  );
};

export default ReviewCardDetails;

我想要跟踪状态以便它可以呈现表单或响应的组件:

import React from 'react';
import ReviewResponse from './ReviewResponse';
import ReviewResponseForm from './ReviewResponseForm';
import { reactLocalStorage } from "reactjs-localstorage";

class ReviewResponseBox extends React.Component {
 // constructor() {
  //  super()

 //   this.state = {
  //    reviewResponses: []
  //  };
//  }

 fetchResponses = () => {
  let reviewResponses = [];
  localStorage.setResponses
  reviewResponses.push(reviewResponse);
}
  
  render () {
    const reviewResponses = this.getResponses();
    const reviewResponseNodes = <div className="reviewResponse-list">{reviewResponses}</div>;
   
    return(
      <div className="reviewResponse-box">
        {reviewResponses.length 
          ? (
            <>
              {reviewResponseNodes}
            </>
          )
          : (
            <ReviewResponseForm addResponse={this.addResponse.bind(this)}/>
          )}
      </div> 
        
    );
  } 
  

  addResponse(review_id, author, body) {
    const reviewResponse = {
      review_id,
      author,
      body
    };
    this.setState({ reviewResponses: this.state.reviewResponses.concat([reviewResponse]) }); // *new array references help React stay fast, so concat works better than push here.
  }
   
  
  
  getResponses() {    
    return this.state.reviewResponses.map((reviewResponse) => { 
      return (
        <ReviewResponse 
          author={reviewResponse.author} 
          body={reviewResponse.body} 
          review_id={this.state.review_id} />
      ); 
    });
  }

  
  
}
export default ReviewResponseBox;

任何指导将不胜感激

【问题讨论】:

    标签: javascript reactjs local-storage state


    【解决方案1】:

    当使用 componentDidUpdate 生命周期方法更新状态时,您可以将响应持久保存到 localStorage。使用componentDidMount生命周期方法读取localStorage值并设置本地组件状态,或者由于从localStorage读取是同步的,直接设置初始状态。

    我认为您也不需要单独的包来处理此问题,您可以轻松使用localStorage API

    import React from "react";
    import ReviewResponse from "./ReviewResponse";
    import ReviewResponseForm from "./ReviewResponseForm";
    
    class ReviewResponseBox extends React.Component {
      state = {
        reviewResponses: JSON.parse(localStorage.getItem(`reviewResponses-${this.props.review_id}`)) || []
      };
    
      storageKey = () => `reviewResponses-${this.props.review_id}`;
    
      componentDidUpdate(prevProps, prevState) {
        if (prevState.reviewResponses !== this.state.reviewResponses) {
          localStorage.setItem(
            `reviewResponses-${this.props.review_id}`,
            JSON.stringify(this.state.reviewResponses)
          );
        }
      }
    
      render() {
        const reviewResponses = this.getResponses();
        const reviewResponseNodes = (
          <div className="reviewResponse-list">{reviewResponses}</div>
        );
    
        return (
          <div className="reviewResponse-box">
            {reviewResponses.length ? (
              <>{reviewResponseNodes}</>
            ) : (
              <ReviewResponseForm addResponse={this.addResponse.bind(this)} />
            )}
          </div>
        );
      }
    
      addResponse(review_id, author, body) {
        const reviewResponse = {
          review_id,
          author,
          body
        };
        this.setState({
          reviewResponses: this.state.reviewResponses.concat([reviewResponse])
        }); // *new array references help React stay fast, so concat works better than push here.
      }
    
      getResponses() {
        return this.state.reviewResponses.map((reviewResponse) => {
          return (
            <ReviewResponse
              author={reviewResponse.author}
              body={reviewResponse.body}
              review_id={this.state.review_id}
            />
          );
        });
      }
    }
    

    【讨论】:

    • 谢谢你,德鲁。这有很大帮助。问题是,现在当我对一条评论发表评论时,该评论会出现在所有评论中。我认为将 review_id 作为道具传递可以解决这个问题,但它似乎没有......
    • @bab 当然......我试图弄清楚是否是这种情况......如果是这样,那么您可以使用计算密钥进行存储,或者嵌套所有单个键中的状态,然后使用评论 ID 访问/更新特定的子状态。前者更简单,即.setItem(`reviewResponses-${id}`, JSON.stringify(.....)).getItem(`reviewResponses-${id}`)
    • 嘿,画了,谢谢。我实现了这一点,但现在出现“未定义 id”的错误
    • 是的,但是您需要在本地定义id,或者从正在审查的评论中获取当前值。哦,我明白了,好像是作为道具传递的,所以在计算存储密钥时使用this.props.review_id
    • 太棒了,成功了!!非常感谢德鲁
    猜你喜欢
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 1970-01-01
    • 2018-12-28
    • 2019-09-20
    • 2020-08-05
    • 2019-09-20
    • 1970-01-01
    相关资源
    最近更新 更多