如何从子组件内部更新 React Context?使用钩子使用类组件

2022-08-30 01:25:18

我在上下文中有语言设置,如下所示

class LanguageProvider extends Component {
  static childContextTypes = {
    langConfig: PropTypes.object,
  };

  getChildContext() {
    return { langConfig: 'en' };
  }

  render() {
    return this.props.children;
  }
}

export default LanguageProvider;

我的应用程序代码将如下所示

<LanguageProvider>
  <App>
    <MyPage />
  </App>
</LanguageProvider>

我的主页具有切换语言的组件

<MyPage>
  <LanguageSwitcher/>
</MyPage>

LanguageSwitcher在这种情况下,需要更新上下文以将语言更改为“jp”,如下所示MyPage

class LanguageSwitcher extends Component {
  static contextTypes = {
    langConfig: PropTypes.object,
  };

  updateLanguage() {
    //Here I need to update the langConfig to 'jp' 
  }

  render() {
    return <button onClick={this.updateLanguage}>Change Language</button>;
  }
}

export default LanguageSwitcher;

如何从语言开关组件内部更新上下文?


答案 1

使用钩子

Hook 在 16.8.0 中引入,因此以下代码需要最低版本 16.8.0(向下滚动以获取类组件示例)。代码沙盒演示

1. 为动态上下文设置父状态

首先,为了有一个可以传递给消费者的动态上下文,我将使用父级的状态。这确保了我有一个单一的事实来源。例如,我的父应用将如下所示:

const App = () => {
  const [language, setLanguage] = useState("en");
  const value = { language, setLanguage };

  return (
    ...
  );
};

存储在状态中。稍后我们将通过上下文传递两者和 setter 函数。languagelanguagesetLanguage

2. 创建上下文

接下来,我创建了一个这样的语言上下文:

// set the defaults
const LanguageContext = React.createContext({
  language: "en",
  setLanguage: () => {}
});

在这里,我设置了('en')的默认值和一个函数,该函数将由上下文提供者发送给消费者。这些只是默认值,在父级中使用提供程序组件时,我将提供它们的值。languagesetLanguageApp

注意:无论您使用钩子还是基于类的组件,都保持不变。LanguageContext

3. 创建上下文使用者

为了让语言切换器设置语言,它应该能够通过上下文访问语言设置器函数。它可能看起来像这样:

const LanguageSwitcher = () => {
  const { language, setLanguage } = useContext(LanguageContext);
  return (
    <button onClick={() => setLanguage("jp")}>
      Switch Language (Current: {language})
    </button>
  );
};

在这里,我只是将语言设置为“jp”,但您可能有自己的逻辑来为此设置语言。

4. 将使用者包装在提供者中

现在,我将以 a 的形式呈现我的语言切换器组件,并将必须通过上下文发送到更深层次的值传入。以下是我父母的样子:LanguageContext.ProviderApp

const App = () => {
  const [language, setLanguage] = useState("en");
  const value = { language, setLanguage };

  return (
    <LanguageContext.Provider value={value}>
      <h2>Current Language: {language}</h2>
      <p>Click button to change to jp</p>
      <div>
        {/* Can be nested */}
        <LanguageSwitcher />
      </div>
    </LanguageContext.Provider>
  );
};

现在,每当单击语言切换器时,它都会动态更新上下文。

代码沙盒演示

使用类组件

最新的上下文 API 是在 React 16.3 中引入的,它提供了一种拥有动态上下文的好方法。以下代码要求最低版本为 16.3.0。代码沙盒演示

1. 为动态上下文设置父状态

首先,为了有一个可以传递给消费者的动态上下文,我将使用父级的状态。这确保了我有一个单一的事实来源。例如,我的父应用将如下所示:

class App extends Component {
  setLanguage = language => {
    this.setState({ language });
  };

  state = {
    language: "en",
    setLanguage: this.setLanguage
  };

  ...
}

与语言 setter 方法一起存储在状态中,您可以将其保留在状态树之外。language

2. 创建上下文

接下来,我创建了一个这样的语言上下文:

// set the defaults
const LanguageContext = React.createContext({
  language: "en",
  setLanguage: () => {}
});

在这里,我设置了('en')的默认值和一个函数,该函数将由上下文提供者发送给消费者。这些只是默认值,在父级中使用提供程序组件时,我将提供它们的值。languagesetLanguageApp

3. 创建上下文使用者

为了让语言切换器设置语言,它应该能够通过上下文访问语言设置器函数。它可能看起来像这样:

class LanguageSwitcher extends Component {
  render() {
    return (
      <LanguageContext.Consumer>
        {({ language, setLanguage }) => (
          <button onClick={() => setLanguage("jp")}>
            Switch Language (Current: {language})
          </button>
        )}
      </LanguageContext.Consumer>
    );
  }
}

在这里,我只是将语言设置为“jp”,但您可能有自己的逻辑来为此设置语言。

4. 将使用者包装在提供者中

现在,我将以 a 的形式呈现我的语言切换器组件,并将必须通过上下文发送到更深层次的值传入。以下是我父母的样子:LanguageContext.ProviderApp

class App extends Component {
  setLanguage = language => {
    this.setState({ language });
  };

  state = {
    language: "en",
    setLanguage: this.setLanguage
  };

  render() {
    return (
      <LanguageContext.Provider value={this.state}>
        <h2>Current Language: {this.state.language}</h2>
        <p>Click button to change to jp</p>
        <div>
          {/* Can be nested */}
          <LanguageSwitcher />
        </div>
      </LanguageContext.Provider>
    );
  }
}

现在,每当单击语言切换器时,它都会动态更新上下文。

代码沙盒演示


答案 2

由于 React 建议使用功能组件和钩子,因此我将使用 useContext 和 useState hooks 实现它。下面介绍如何从子组件中更新上下文。

语言上下文管理.js

import React, { useState } from 'react'

export const LanguageContext = React.createContext({
  language: "en",
  setLanguage: () => {}
})

export const LanguageContextProvider = (props) => {

  const setLanguage = (language) => {
    setState({...state, language: language})
  }

  const initState = {
    language: "en",
    setLanguage: setLanguage
  } 

  const [state, setState] = useState(initState)

  return (
    <LanguageContext.Provider value={state}>
      {props.children}
    </LanguageContext.Provider>
  )
}

应用程序.js

import React, { useContext } from 'react'
import { LanguageContextProvider, LanguageContext } from './LanguageContextManagement'

function App() {

  const state = useContext(LanguageContext)

  return (
    <LanguageContextProvider>
      <button onClick={() => state.setLanguage('pk')}>
        Current Language is: {state.language}
      </button>
    </LanguageContextProvider>
  )
}

export default App