web-dev-qa-db-ja.com

Reactギャツビープロダクションモードでの最初のレンダリングではフックが正しく機能しません

次の問題があります。

Jsのcssにgatsbyを使用するemotionウェブサイトがあります。私は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値、OSカラースキームをチェックし、デフォルトはfalseです。アプリケーションを実行してダークモードをアクティブにすると、localStorageの値が設定されます。アプリケーションをリロードすると、getInitialIsDarkメソッドはtrueを返しますが、UIはライトテーマをレンダリングします。明暗の切り替えは期待どおりに機能し、初期ロードだけでは機能しません。

GetInitialIsDarkをtrueに置き換えると、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>
  )
}

しかし、これはページの読み込み時に醜いちらつきを引き起こします。

最初のアプローチのフックで何が問題になっていますか?初期値が期待どおりに機能していません。

4
Console

同様の問題があり、一部のスタイルは、マウント時に設定されたクラスを介して適用されたために有効になりませんでした(プロダクションビルドでのみのように、すべてが開発で正常に機能しました)。

私はハイドレート関数を切り替えることになりましたReactはReactDOM.hydrateからReactDOM.renderに使用していたため、問題は解消しました。

// gatsby-browser.js
export const replaceHydrateFunction = () => (element, container, callback) => {
  ReactDOM.render(element, container, callback);
};
0
locrizak

これは私のために働いたものです、これを試して、うまくいったかどうか私に知らせてください。

最初

に src/components / コンポーネントを作成しました navigation.js

    export default class Navigation extends Component {
      static contextType = ThemeContext // eslint-disable-line
      render() {
        const theme = this.context  
        return (
          <nav className={'nav scroll' : 'nav'}>
            <div className="nav-container">
               <button
                 className="dark-switcher"
                 onClick={theme.toggleDark}
                 title="Toggle Dark Mode"
                >
              </button>
            </div>
          </nav>
        )
      }
    }

二番目

作成した gatsby-browser.js

    import React from 'react'
    import { ThemeProvider } from './src/context/ThemeContext'

    export const wrapRootElement = ({ element }) => <ThemeProvider>{element}</ThemeProvider>

第三

ThemeContext.jsファイルをsrc/context /に作成しました

    import React, { Component } from 'react'

    const defaultState = {
      dark: false,
      notFound: false,
      toggleDark: () => {},
    }

    const ThemeContext = React.createContext(defaultState)

    class ThemeProvider extends Component {
      state = {
        dark: false,
        notFound: false,
      }

      componentDidMount() {
        const lsDark = JSON.parse(localStorage.getItem('dark'))

        if (lsDark) {
          this.setState({ dark: lsDark })
        }
      }

      componentDidUpdate(prevState) {
        const { dark } = this.state

        if (prevState.dark !== dark) {
          localStorage.setItem('dark', JSON.stringify(dark))
        }
      }

      toggleDark = () => {
        this.setState(prevState => ({ dark: !prevState.dark }))
      }

      setNotFound = () => {
        this.setState({ notFound: true })
      }

      setFound = () => {
        this.setState({ notFound: false })
      }

      render() {
        const { children } = this.props
        const { dark, notFound } = this.state

        return (
          <ThemeContext.Provider
            value={{
              dark,
              notFound,
              setFound: this.setFound,
              setNotFound: this.setNotFound,
              toggleDark: this.toggleDark,
            }}
          >
            {children}
          </ThemeContext.Provider>
        )
      }
    }

    export default ThemeContext

    export { ThemeProvider }

これはあなたのために働くはずです 公式ギャツビーサイト から私が従ったリファレンスです

0
Waleed