0

我将主题状态作为反冲原子来管理。

如果用户通过 ui 改变主题,对应的 atom 状态也会改变。

我想将此处更改的主题值保存到本地存储。为此,我们需要知道该状态何时发生变化。

当然,你可以在调用对应的 atom 状态改变之前添加 localstorage 存储代码,但是如果在很多地方使用 atom 的话,这样效率太低了。

此时我应该使用选择器吗?但是,由于主题是单个状态,因此将其作为派生状态来扩展状态变化逻辑并不直观。

如果您知道,任何帮助将不胜感激。

示例代码

import { StrictMode } from "react";
import ReactDOM from "react-dom";
import { RecoilRoot, atom, useRecoilState } from "recoil";

type ThemeItem = "light" | "dark";
// : I want to do some extra work when this state changes (ex: Save the changed state to localStorage)
const themeState = atom<ThemeItem>({
  key: "themeState",
  default: "light",
});

function App() {
  const [theme, setTheme] = useRecoilState(themeState);

  function handleTheme(theme: ThemeItem) {
    return () => setTheme(theme);
  }

  return (
    <>
      <h3>{theme}</h3>
      <button onClick={handleTheme("light")}>light</button>
      <button onClick={handleTheme("dark")}>dark</button>
    </>
  );
}

ReactDOM.render(
  <StrictMode>
    <RecoilRoot>
      <App />
    </RecoilRoot>
  </StrictMode>,
  document.getElementById("root")
);
4

1 回答 1

0

我之前解决这个问题的方法是实现一个ThemeProvider(或任何你想称之为的),然后useEffect同时使用存储和加载值localStorage

import { StrictMode, useEffect } from "react";
import ReactDOM from "react-dom";
import { RecoilRoot, atom, useRecoilState } from "recoil";

type ThemeItem = "light" | "dark";
// : I want to do some extra work when this state changes (ex: Save the changed state to localStorage)
const themeState = atom<ThemeItem>({
  key: "themeState",
  default: "light",
});

function ThemeProvider() {
  const [theme, setTheme] = useRecoilState(themeState);

  useEffect(() => {
    // Save theme in localStorage on change
    localStorage.setItem('theme', theme);
  }, [theme]);

  useEffect(() => {
    // Load theme from localStorage on mount
    if (!localStorage.getItem('theme')) return;
    setTheme(localStorage.getItem('theme') as ThemeItem);
  }, []);
}

function App() {
  const [theme, setTheme] = useRecoilState(themeState);

  function handleTheme(theme: ThemeItem) {
    return () => setTheme(theme);
  }

  return (
    <>
      <h3>{theme}</h3>
      <button onClick={handleTheme("light")}>light</button>
      <button onClick={handleTheme("dark")}>dark</button>
    </>
  );
}

ReactDOM.render(
  <StrictMode>
    <RecoilRoot>
      <ThemeProvider />
      <App />
    </RecoilRoot>
  </StrictMode>,
  document.getElementById("root")
);
于 2021-09-11T10:33:52.720 回答