【问题标题】:State managed in Context is showing undefined上下文中管理的状态显示未定义
【发布时间】:2020-04-11 15:46:08
【问题描述】:

我正在实施一个黑暗主题来理解 React 上下文。我成功创建了一个将模式保存到本地存储的暗模式,并确定用户是否更喜欢本地存储中的暗模式。 但是现在我想重构以保持主题状态在上下文中。 我已经在主题上下文中移动了代码,但是我得到了错误说明

错误: TypeError: Cannot read property 'darkMode' of undefined

我似乎无法解决。我的印象是我可以使用 useContext 将这种情况下的状态 darkMode 和 setDarkMode 传递到我的 App 组件中?

import React, { useContext } from 'react';
import ThemeContextProvider, { ThemeContext } from './contexts/ThemeContext';


function App() {
  const { darkMode, setDarkMode } = useContext(ThemeContext);
  return (
    <div className='App'>
      <ThemeContextProvider>
        <div className={darkMode ? 'dark-mode' : 'light-mode'}>
          <nav>
            <div className='toggle-container'>
              <span style={{ color: darkMode ? 'grey' : 'yellow' }}>☀︎</span>
              <span className='toggle'>
                <input
                  checked={darkMode}
                  onChange={() => setDarkMode((prevMode) => !prevMode)}
                  type='checkbox'
                  className='checkbox'
                  id='checkbox'
                />
                <label htmlFor='checkbox' />
              </span>
              <span style={{ color: darkMode ? '#9c27b0' : 'grey' }}>☽</span>
            </div>
          </nav>
          <main>
            <h1>{darkMode ? 'Dark Mode' : 'Light Mode'}</h1>
            <h2>Toggle the switch to change theme</h2>
          </main>
        </div>
      </ThemeContextProvider>
    </div>
  );
}

和 ThemeContext

import React, { createContext, useState, useEffect } from 'react';

export const ThemeContext = createContext();

const ThemeContextProvider = (props) => {
  const [darkMode, setDarkMode] = useState(getInitialMode);

  useEffect(() => {
    localStorage.setItem('dark', JSON.stringify(darkMode));
    getPrefColourScheme();
  }, [darkMode]);

  function getInitialMode() {
    const isReturningUser = 'dark' in localStorage;
    const savedMode = JSON.parse(localStorage.getItem('dark'));
    const userPrefersDark = getPrefColourScheme();
    // if mode was saved -> dark / light
    if (isReturningUser) {
      return savedMode;
      // if preferred colour scheme is dark -> dark
    } else if (userPrefersDark) {
      return true;
      // otherwise -> light
    } else {
      return false;
    }
  }

  function getPrefColourScheme() {
    if (!window.matchMedia) return;

    return window.matchMedia('(prefers-color-scheme: dark)').matches;
  }
  return (
    <ThemeContext.Provider value={{ darkMode, setDarkMode }}>
      {props.children}
    </ThemeContext.Provider>
  );
};
export default ThemeContextProvider;

请原谅我的无知,我正在努力解决这个问题。 任何帮助将不胜感激。

【问题讨论】:

    标签: reactjs react-hooks react-context


    【解决方案1】:

    我认为你只能使用

    const { darkMode, setDarkMode } = useContext(ThemeContext);

    只要使用此钩子的组件之上的某个组件具有&lt;Context.Provider&gt;

    但是,您在 App 组件中使用了这个钩子 - 它不是您的 Provider 的子组件。

    您可以做的是将子组件分离到一个新组件并在那里使用钩子,或者将您的 &lt;App /&gt; 渲染为您的 &lt;ThemeContextProvider&gt; 的子组件(这意味着将您的 &lt;ThemeContextProvider&gt; 移动到另一个地方)

    选项 1

     const FooComp = () => {
        const { darkMode, setDarkMode } = useContext(ThemeContext);
    return (
        <div className={darkMode ? 'dark-mode' : 'light-mode'}>
                  <nav>
                    <div className='toggle-container'>
                      <span style={{ color: darkMode ? 'grey' : 'yellow' }}>☀︎</span>
                      <span className='toggle'>
                        <input
                          checked={darkMode}
                          onChange={() => setDarkMode((prevMode) => !prevMode)}
                          type='checkbox'
                          className='checkbox'
                          id='checkbox'
                        />
                        <label htmlFor='checkbox' />
                      </span>
                      <span style={{ color: darkMode ? '#9c27b0' : 'grey' }}>☽</span>
                    </div>
                  </nav>
                  <main>
                    <h1>{darkMode ? 'Dark Mode' : 'Light Mode'}</h1>
                    <h2>Toggle the switch to change theme</h2>
                  </main>
                </div>
    )
        }
    

    然后在App

    function App() {
      return (
        <div className='App'>
          <ThemeContextProvider><FooComp /></ThemeContextProvider>
        )
    }
    

    选项2

    在你渲染App的地方

    <ThemeContextProvider><App /></ThemeContextProvider>
    
    

    然后你从App 中删除ThemeContextProvider

    【讨论】:

      【解决方案2】:

      如果您正在使用类组件并遇到此问题 上下文存储在类组件中称为上下文的变量中

          import React, {Component, useContext} from 'react';
          import {ThemeContext} from '../contexts/ThemeContext';
      
      
      
          class Navbar extends Component {
      
          static contextType = ThemeContext
      
          render() {
              console.log(this.context); 
              return ( 
                  <nav>
                      <h1>Content Apps</h1>
                      <ul>
                          <li>Home</li>
                          <li>About</li>
                          <li>Contact</li>
                      </ul>
                  </nav>
               );
          }
      }
      
      export default Navbar;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-04-07
        • 2021-11-15
        • 2023-02-14
        • 1970-01-01
        • 1970-01-01
        • 2019-10-23
        • 1970-01-01
        • 2011-06-17
        相关资源
        最近更新 更多