You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React食谱应用星级评分本地存储失效问题求助

解决食谱应用评分无法存入localStorage的问题

问题根源分析

你的代码存在几个关键问题导致评分无法存入localStorage:

  • 误用useCallback处理副作用:useCallback是用来缓存函数的,不是执行存储这类副作用的,应该用useEffect。
  • 未解析localStorage的字符串数据:从localStorage.getItem拿到的是JSON字符串,直接给它加属性不会生效,必须转成对象。
  • 缺失React钩子导入:代码里用了useState、useEffect但没导入,会引发运行错误。
  • 依赖项不全:存储逻辑依赖details.id,但之前的依赖数组没加,初始时details是空对象,id不存在会导致存储键错误。
  • 未读取已有评分:组件挂载时没从localStorage加载之前的评分,无法恢复用户历史评分。

修正后的完整代码

import styled from "styled-components";
import Searched from "../Pages/Searched";
import { useParams, useState, useEffect } from "react"; // 补充React钩子导入

const StarRating = () => {
  let params = useParams();
  const [details, setDetails] = useState({});
  const [activeTab, setActiveTab] = useState("instructions");
  const [rating, setRating] = useState(0);
  const [hover, setHover] = useState(0);

  const fetchDetails = async () => {
    const data = await fetch(
      `https://api.spoonacular.com/recipes/${params.name}/information?apiKey=${process.env.REACT_APP_API_KEY}`
    );
    const detailData = await data.json();
    setDetails(detailData);
  };

  useEffect(() => {
    fetchDetails();
  }, [params.name]);

  // 组件挂载后读取已有评分
  useEffect(() => {
    if (details.id) {
      const storedRatings = JSON.parse(localStorage.getItem("rating")) || {};
      if (storedRatings[details.id]) {
        setRating(storedRatings[details.id]);
      }
    }
  }, [details.id]);

  // 评分变化时更新localStorage
  useEffect(() => {
    if (details.id) {
      const storedRatings = JSON.parse(localStorage.getItem("rating")) || {};
      storedRatings[details.id] = rating;
      localStorage.setItem("rating", JSON.stringify(storedRatings));
    }
  }, [rating, details.id]);

  return (
    <StarStyle>
      <div className="star-rating">
        {[...Array(5)].map((star, index) => {
          index += 1;
          return (
            <button
              type="button"
              key={index}
              className={index <= (hover || rating) ? "on" : "off"}
              onClick={() => setRating(index)}
              onMouseEnter={() => setHover(index)}
              onMouseLeave={() => setHover(rating)}
            >
              <span className="star">&#9733;</span>
            </button>
          );
        })}
      </div>
    </StarStyle>
  );
};

export default StarRating;

const StarStyle = styled.form`
  button {
    background-color: transparent;
    border: none;
    outline: none;
    cursor: pointer;
    block-size: 150px;
    font-size: 60px;
  }
  .on {
    color: #000;
  }
  .off {
    color: #ccc;
  }
`;

关键修改说明

  1. 替换useCallback为useEffect:用useEffect处理存储和读取的副作用,符合React的副作用处理规范。
  2. 解析localStorage数据:每次读取rating时用JSON.parse转成对象,修改后用JSON.stringify存回,确保数据格式正确。
  3. 补充钩子导入:添加useState、useEffect的导入,避免运行时错误。
  4. 完善依赖数组:存储逻辑的依赖数组加入details.id,确保只有当食谱ID存在且评分变化时才执行存储。
  5. 添加初始评分读取:组件挂载后,当details.id存在时,从localStorage读取对应食谱的评分并同步到状态。
  6. 增加存在性判断:在存储和读取时都判断details.id是否存在,避免初始阶段details为空对象导致的无效存储。

内容的提问来源于stack exchange,提问作者raul atofanei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 07:39:59