Redux-Persistent不持久化状态的一个切片

unhi4e5o  于 2023-05-29  发布在  其他
关注(0)|答案(1)|浏览(143)

我在一个有多个状态切片的React应用程序中使用react-redux和redux-persistent。这是一个简单的应用程序,包含uitodolistnotestodolist-projects等切片。除了todolist片之外,所有的状态片都是持久的。
下面是我的store/index.js,我在其中初始化了存储和持久化器:

import { legacy_createStore as createStore } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import { rootReducer } from "./rootReducer";
import storage from "redux-persist/lib/storage";

const persistConfig = {
  key: "root",
  storage,
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

export const store = createStore(
  persistedReducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export const persistor = persistStore(store);

我在GitHub的一个问题中读到了一些关于key的prop有时需要设置为"primary"而不是"root"。在Chrome DevTools的localStorage调试区域中,我注意到todolist切片似乎确实存在于persist:primary部分。(见下面的屏幕截图。)x1c 0d1x
我尝试将key"root"更改为"primary",但这似乎不起作用。看起来没什么区别。
你可以在CodeSandbox上看到这个项目

5uzkadbs

5uzkadbs1#

问题

state.todolist被持久化到localStorage,正如您的屏幕截图所示。不过,我在你的沙箱中发现了一些代码问题。

  1. NavBar使用原始锚(<a>)标记而不是react-router-domLink组件来实现导航操作。这些将重新加载页面并重置任何本地React组件状态。
  2. Todolist组件使用了错误的对象引用比较来根据当前state.ui.currTodoProject值筛选选定的state.todolist状态。这些都是对象,在状态被JSON序列化到localStorage中,然后JSON反序列化回到Redux存储中之后,它们将不再具有浅引用相等性......它们是全新的不同的物体。

建议方案

更新NavBar以使用Link组件。

import "./NavBar.styles.css";
import { Link } from "react-router-dom";
import { persistor } from "../../../store/index.js";

const NavBar = () => {
  const purgeCache = () => {
    persistor
      .purge()
      .then(() => console.log("Cache Pruged!"))
      .catch(() => console.log("Could Not Purge Cache..."));
  };
  
  return (
    <nav>
      <ul>
        <li>
          <Link to="/todolist">Todo List</Link>
        </li>
        <li>
          <Link to="/notes">Notes</Link>
        </li>
        <li style={{ float: "right" }} onClick={purgeCache}>
          <Link to="/">Purge Store</Link>
        </li>
      </ul>
    </nav>
  );
};

export default NavBar;

更新Todolist通过_id属性比较项目对象 *。也不需要将todolist复制到任何本地状态,只需从选定的todolist状态计算当前currTodos值。

const currTodos = todolist.filter(
  (t) => t.project._id === ui.currTodoProject._id
);

如果计算这个派生的状态是昂贵的,使用useMemo钩子来记忆计算的值。事实上,几乎任何时候你看到自己在写useState/useEffect钩子组合,这就是useMemo的用途。

const currTodos = useMemo(() => todolist.filter(
  (t) => t.project._id === ui.currTodoProject._id
), [todolist, ui.currTodoProject._id]);
...

const Todolist = () => {
  const todolist = useSelector((state) => state.todolist);
  const projects = useSelector((state) => state.todolistProjects);
  const ui = useSelector((state) => state.ui);
  const dispatch = useDispatch();

  const [deletedTodo, setDeletedTodo] = useState({});

  useEffect(() => {
    dispatch(changeTodoProject(projects[0]));
  }, []);

  const currTodos = todolist.filter(
    (t) => t.project._id === ui.currTodoProject._id
  );
  
  ...

  return (
    <div id="todolist" onClick={handleContainerClick}>
      ...
      {currTodos.map((todo) => {
        return (
          <Todo
            todo={todo}
            key={todo._id}
            showDeleteDialog={showDeleteDialog}
            setDeletedTodo={setDeletedTodo}
          />
        );
      })}
      ...
    </div>
  );
};

export default Todolist;

相关问题