我有以下问题:

我有一个gatsby网站,该网站在js中将emotion用于CSS。我使用emotion theming实现暗模式。当我运行gatsby develop时,暗模式可以按预期工作,但如果我使用gatsby build && gatsby serve运行它,则无法使用。更具体地说,暗模式仅在切换到亮然后再次返回后才起作用。

我必须遵循以下处理主题的顶级组件:

const Layout = ({ children }) => {
  const [isDark, setIsDark] = useState(() => getInitialIsDark())

  useEffect(() => {
    if (typeof window !== "undefined") {
      console.log("save is dark " + isDark)
      window.localStorage.setItem("theming:isDark", isDark.toString())
    }
  }, [isDark])

  return (
    <ThemeProvider theme={isDark ? themeDark : themeLight}>
      <ThemedLayout setIsDark={() => setIsDark(!isDark)} isDark={isDark}>{children}</ThemedLayout>
    </ThemeProvider>
  )
}
getInitalIsDark函数检查localStorage值,操作系统配色方案,并且默认为false。如果我运行该应用程序,然后激活暗模式,则将设置localStorage值。如果我现在重新加载应用程序,则getInitialIsDark方法将返回true,但UI会渲染浅色主题。在明亮和黑暗之间来回切换按预期工作,只是初始负载不起作用。

如果我用true替换getInitialIsDark,则darkMode会按预期工作,但lightMode会损坏。我使它起作用的唯一方法是使用以下代码在按时加载后自动重新渲染。
const Layout = ({ children }) => {
  const [isDark, setIsDark] = useState(false)
  const [isReady, setIsReady] = useState(false)

  useEffect(() => {
    if (typeof window !== "undefined" && isReady) {
      console.log("save is dark " + isDark)
      window.localStorage.setItem("theming:isDark", isDark.toString())
    }
  }, [isDark, isReady])

  useEffect(() => setIsReady(true), [])
  useEffect(() => {
    const useDark = getInitialIsDark()
    console.log("init is dark " + useDark)
    setIsDark(useDark)
  }, [])

  return (
    <ThemeProvider theme={isDark ? themeDark : themeLight}>
      {isReady ? (<ThemedLayout setIsDark={() => setIsDark(!isDark)} isDark={isDark}>{children}</ThemedLayout>) : <div/>}
    </ThemeProvider>
  )
}

但这会导致页面加载时出现难看的闪烁。

我在第一种方法中使用钩子(Hook)做错了什么,即初始值未按我期望的那样工作。

最佳答案

您是否尝试过像这样设置初始状态?
const [isDark, setIsDark] = useState(getInitialIsDark())
请注意,我没有将getInitialIsDark()包装在其他函数中:
useState(() => getInitialIsDark())
您可能会导致构建崩溃,因为在构建时未定义localStorage。您可能需要检查getInitialIsDark中是否存在。

希望这可以帮助!

09-25 17:00