对这个概念最初的认知来自于某个缠身于作者负面信息的国人吸血鬼漫画,但是自从Notion诞生开始,这个概念就不是什么科幻的存在。世间存在的知识远远超过一个人可以穷尽和记忆的数量,游戏有攻略有秘籍,那么地球Online自然也需要一本秘籍,也就是外部脑这个概念,说白了就是一本随时随地可以翻出来供自己快速回顾自己走通的东西的记事本,但是内容跨度是一辈子罢了。

以下所有内容都未必是最佳实践,涉及到的代码未必完整,注释未必清晰甚至未必会有注释,仅作为未来或许会用得上的hint记忆使用。

1. ReactJS MUI 夜间模式/深色模式 + 跟随系统 + 记忆
夜间模式Drawer部件
夜间模式Drawer内控制部件
import { ThemeProvider, createTheme } from '@mui/material/styles';

function App() {
  const [isFollowSysTheme, setIsFollowSysTheme] = useState(localStorage.getItem('ThemeFollow') === 'false' ? false : true);
  const [mode, setMode] = useState(checkIsDarkMode());

  // 夜间模式检查
  function checkIsDarkMode() {
    if (isFollowSysTheme) {
      try {
        return window.matchMedia('(prefers-color-scheme: dark)').matches;
      } catch (err) {
        return false;
      }
    } else {
      return localStorage.getItem('NightMode') === 'true' ? true : false
    }
  }

  // 使用createTheme Override对应部件样式
  const appTheme = createTheme({
    palette: {
      mode: mode ? 'dark' : 'light',
    },
    components: {
      MuiDialogContent: {
        styleOverrides: {
          root: {
            '&.Roadmap' : {
              color: mode ? '#c9c2b7' : '#242525',
              background: mode ? '#242525' : '#eeeeee',
            },
            '&.About': {
              color: mode ? '#c9c2b7' : '#242525',
              background: mode ? '#242525' : '#eeeeee',
            },
          },
        },
      },
      MuiListItemText: {
        styleOverrides: {
          root: {
            color: mode ? '#c9c2b7' : '#242525',
          },
        },
      },
    },
  });
  
  // 两个借助localStorage实现记忆的handle
  const handleFollow = () => {
    localStorage.setItem('ThemeFollow', !isFollowSysTheme);
    setIsFollowSysTheme(!isFollowSysTheme);
    window.location.reload();
  }

  const handleMode = () => {
    localStorage.setItem('NightMode', !mode);
    setMode(!mode);
  };

  return (
    <div className="App">
      <header className="App-header">

      <ThemeProvider theme={appTheme}>
        {Contents}
      </ThemeProvider>
      
      </header>
    </div>
  )

2. React 环境变量调用
const Var1 = process.env.REACT_APP_VAR_1;

3. LocalStorage存取json设置与初始化 + useContext
// Settings.js
import ...

// Context
// 其他文件通过导入useSettings就可以使用const { layout, columns } = useSettings();获得
export function useSettings() {
    const context = React.useContext(SettingsContext);
    if (!context) throw new Error("useSettings must be used within a SettingsContext");
    return context;
}

export default function Settings({ children }) {
  // 拿不到浏览器存的才用默认值
  const userSettings = JSON.parse(localStorage.getItem("userLayoutSettings"));
  const [layout, setLayout] = React.useState(userSettings ? userSettings.layout : "rows");
  const [columns, setColumns] = React.useState(userSettings ? userSettings.columns : 2);

  const settings = React.useMemo(
        () => ({
            layout,
            columns,
        }),
        [layout, columns],
    );

  // settings有变动就存浏览器上
  useLayoutEffect(() => {
        localStorage.setItem("userLayoutSettings", JSON.stringify(settings));
        console.log("SET userLayoutSettings: ", JSON.stringify(settings));
    }, [settings])

  // 浏览器没存setting就根据window.innerWidth来决定第一次初始化&保存的值
  useLayoutEffect(() => {
        if (!userSettings) {
            const viewportSize = window.innerWidth;
            setColumns(viewportSize < 480 ? 2 : viewportSize < 900 ? 3 : 4);
        }
    }, [userSettings]);

  return (
    <SettingsContext.Provider value={settings}>
      {children}
    </SettingsContext.Provider>
  );
}

// App.js
import ...

// 原来app的内容
function AppContent() {
  return (
    ...
  )
}

// 用Settings包住AppContent才能正常用,额外变量和逻辑也可以放这里
export default function App() {

  const [var1, setVar1] = useState([]);

  return (
    <Settings>
      <AppContent var1={var1}...>
    </Settings>
  )
}

4. React-router-dom

咕咕咕……