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

React开发待办类观剧列表,页面刷新后Local Storage数据丢失如何解决?

问题根因

  1. 缓存读写逻辑位置完全错位
    你把剧集列表的缓存读取逻辑写在了子组件MyWatchListItem里,且读出来的数据赋值给了控制编辑状态的edit变量,根本没有更新真正用来渲染列表的watchLists状态(该状态存储在父组件MyWatchList中)。
  2. 父组件状态初始化未读取缓存
    主组件MyWatchList中watchLists的初始值直接写死为空数组,页面刷新后状态自然回到空值。
  3. 子组件缓存写入逻辑未加依赖,导致初始渲染直接覆盖原有缓存
    MyWatchListItem中写入localStorage的useEffect没有添加依赖数组,组件第一次渲染时父组件传过来的watchLists还是初始空值,该钩子直接执行把空数组写入localStorage,之前存储的有效数据直接被清空。

修改方案

1. 调整主组件MyWatchList逻辑

将缓存读写逻辑移到存储watchLists状态的主组件中,初始化时读缓存,状态变化时写缓存:

// 新增导入useEffect
import React, { useState, useEffect } from "react";
import { MyWatchListForm } from "./MyWatchListForm";
import { MyWatchListItem } from "./MyWatchListItem";

export const MyWatchList = () => {
  // 初始化从localStorage读数据,读不到则用空数组
  const [watchLists, setWatchLists] = useState(() => {
    const savedData = localStorage.getItem("my-watchList");
    return savedData ? JSON.parse(savedData) : [];
  });

  // 监听watchLists变化,更新缓存
  useEffect(() => {
    localStorage.setItem("my-watchList", JSON.stringify(watchLists));
  }, [watchLists]);

  // 原有新增、编辑、删除、完成逻辑无需改动,直接保留即可
  const addWatchList = (watchList) => {
    if (!watchList.text || /^\s*$/.test(watchList.text)) {
      return;
    }
    const newWatchList = [watchList, ...watchLists];
    setWatchLists(newWatchList);
  };

  const updateWatchList = (watchListId, newValue) => {
    if (!newValue.text || /^\s*$/.test(newValue.text)) {
      return;
    }
    setWatchLists((prev) =>
      prev.map((item) => (item.id === watchListId ? newValue : item))
    );
  };

  const removeWatchList = (id) => {
    const removeArr = [...watchLists].filter((watchList) => watchList.id !== id);
    setWatchLists(removeArr);
  };

  const completeWatchList = (id) => {
    const updatedWatchList = watchLists.map((watchList) => {
      if (watchList.id === id) {
        watchList.isComplete = !watchList.isComplete;
      }
      return watchList;
    });
    setWatchLists(updatedWatchList);
  };

  return (
    <div>
      <h1>Watch later</h1>
      <MyWatchListForm onSubmit={addWatchList} />
      <MyWatchListItem
        watchLists={watchLists}
        completeWatchList={completeWatchList}
        removeWatchList={removeWatchList}
        updateWatchList={updateWatchList}
      />
    </div>
  );
};

2. 清理子组件MyWatchListItem冗余逻辑

删掉子组件中错位的缓存读写逻辑即可:

import React, { useState } from "react";
import { RiCloseCircleLine } from "react-icons/ri";
import { TiEdit } from "react-icons/ti";
import { MyWatchListForm } from "./MyWatchListForm";

export const MyWatchListItem = ({
  watchLists,
  completeWatchList,
  removeWatchList,
  updateWatchList,
}) => {
  const [edit, setEdit] = useState({
    id: null,
    value: "",
  });

  const submitUpdate = (value) => {
    updateWatchList(edit.id, value);
    setEdit({
      id: null,
      value: "",
    });
  };

  // 删掉原有两个操作localStorage的useEffect,冗余且逻辑错误

  if (edit.id) {
    return <MyWatchListForm edit={edit} onSubmit={submitUpdate} />;
  }

  return watchLists.map((watchList, index) => (
    <div className={watchList.isComplete ? "checked" : ""} key={index}>
      <div key={watchList.id} onClick={() => completeWatchList(watchList.id)}>
        {watchList.text}
      </div>
      <div>
        <RiCloseCircleLine onClick={() => removeWatchList(watchList.id)} />
        <TiEdit
          onClick={() => setEdit({ id: watchList.id, value: watchList.text })}
        />
      </div>
    </div>
  ));
};

3. 补充MyWatchListForm的缺失依赖

你的表单组件漏了React钩子的导入,同时自动聚焦的useEffect要加空依赖避免重复执行:

// 顶部新增导入
import React, { useState, useRef, useEffect } from "react";

export const MyWatchListForm = (props) => {
  const [input, setInput] = useState(props.edit ? props.edit.value : "");
  const inputRef = useRef();

  // 加空依赖数组,只在组件挂载时执行一次聚焦
  useEffect(() => {
    inputRef.current.focus();
  }, []);

  // 原有提交、输入逻辑无需改动
  const handleSubmit = (e) => {
    e.preventDefault();
    props.onSubmit({
      id: Math.floor(Math.random() * 10000),
      text: input,
    });
    setInput("");
  };

  const handleChange = (e) => {
    setInput(e.target.value);
  };

  return (
    <form
      className="w-full max-w-sm flex items-center border-b border-teal-500 py-2"
      onSubmit={handleSubmit}
    >
      {props.edit ? (
        <>
          <input
            className="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none"
            type="text"
            value={input}
            placeholder="Update the episode"
            onChange={handleChange}
            ref={inputRef}
          ></input>
          <button>Update</button>
        </>
      ) : (
        <>
          <input
            className="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none"
            type="text"
            value={input}
            placeholder="Add the episode"
            onChange={handleChange}
            ref={inputRef}
          ></input>
          <button>Add</button>
        </>
      )}
    </form>
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 17:42:00