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

React食谱应用收藏功能异常:如何不可变更新数组并持久化到localStorage

食谱收藏功能修复方案

问题现状

切换食谱页面添加新收藏时,原有收藏会被清空;重复添加同一食谱无法去重;进入已收藏食谱页面时,按钮状态未同步。

原因分析

  1. AddToFavorites组件初始化favorites状态时未读取localStorage已有数据,每次挂载都从空数组开始
  2. 状态更新未使用函数式更新,存在异步状态覆盖风险
  3. 未实现removeFromFavorites函数,且按钮初始状态未根据收藏列表判断
  4. Favorites组件未解析localStorage存储的JSON字符串,直接使用会导致渲染错误

修复方案

1. 重构AddToFavorites组件

修改状态初始化逻辑,从localStorage读取已有收藏,同步按钮状态,并实现完整的增删逻辑:

function AddToFavorites({ details }) {
  // 从localStorage读取并解析收藏列表,为空则设为[]
  const [favorites, setFavorites] = useState(() => {
    const storedFavs = localStorage.getItem('favorites');
    return storedFavs ? JSON.parse(storedFavs) : [];
  });

  // 初始化按钮状态:判断当前食谱是否已在收藏中
  const [active, setActive] = useState(() => {
    return favorites.some(fav => fav.id === details.id);
  });

  const handleActive = () => {
    setActive(!active);
  };

  const addToFavorites = () => {
    // 函数式更新确保基于最新状态操作
    setFavorites(prevFavs => {
      // 避免重复添加同一食谱
      if (prevFavs.some(fav => fav.id === details.id)) return prevFavs;
      const newFavs = [...prevFavs, details];
      localStorage.setItem('favorites', JSON.stringify(newFavs));
      return newFavs;
    });
  };

  const removeFromFavorites = () => {
    setFavorites(prevFavs => {
      const newFavs = prevFavs.filter(fav => fav.id !== details.id);
      localStorage.setItem('favorites', JSON.stringify(newFavs));
      return newFavs;
    });
  };

  const handleFavorites = () => {
    handleActive();
    active ? removeFromFavorites() : addToFavorites();
  };

  return (
    <AddToFavBtn className={active ? 'active' : null} onClick={handleFavorites}>
      {!active ? 'Add to favorites' : 'Remove from favorites'}
      <div>
        <BsFillSuitHeartFill />
      </div>
    </AddToFavBtn>
  );
}

2. 修复Favorites组件渲染逻辑

解析localStorage数据,处理空状态,并添加跨页面状态同步监听:

function Favorites() {
  const [favList, setFavList] = useState(() => {
    const storedFavs = localStorage.getItem('favorites');
    return storedFavs ? JSON.parse(storedFavs) : [];
  });

  // 监听localStorage变化,实现跨页面收藏状态实时同步
  useEffect(() => {
    const syncFavorites = () => {
      const storedFavs = localStorage.getItem('favorites');
      setFavList(storedFavs ? JSON.parse(storedFavs) : []);
    };
    window.addEventListener('storage', syncFavorites);
    return () => window.removeEventListener('storage', syncFavorites);
  }, []);

  return (
    <FavPageContainer>
      {favList.length === 0 ? (
        <p>No favorite recipes yet.</p>
      ) : (
        <ul>
          {favList.map(item => (
            <li key={item.id}>
              <h3>{item.title}</h3>
              <img src={item.image} alt={item.title} width="100" />
            </li>
          ))}
        </ul>
      )}
    </FavPageContainer>
  );
}

关键修复点说明

  • 状态初始化:使用函数式useState确保仅在组件挂载时读取一次localStorage,避免重复解析
  • 函数式状态更新:通过setFavorites(prev => ...)保证每次操作基于最新状态,解决异步覆盖问题
  • 去重处理:添加收藏前检查食谱ID,避免重复存储
  • 按钮状态同步:初始化时判断当前食谱是否在收藏列表,进入页面时按钮状态正确
  • 跨页面同步:监听storage事件,实现不同页面间收藏状态实时更新

内容的提问来源于stack exchange,提问作者Christoper Chamberlain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 02:47:06