javascript 使用 React Hook of useContext 时如何更改 Context 值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/54738681/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:26:35  来源:igfitidea点击:

How to change Context value while using React Hook of useContext

javascriptreactjsreact-hooksreact-context

提问by Randy Burgess

Using the useContexthook with React 16.8+ works well. You can create a component, use the hook, and utilize the context values without any issues.

useContextReact 16.8+ 中使用钩子效果很好。您可以创建一个组件、使用钩子并使用上下文值而不会出现任何问题。

What I'm not certain about is how to apply changes to the Context Provider values.

我不确定的是如何将更改应用于 Context Provider 值。

1) Is the useContext hook strictly a means of consuming the context values?

1) useContext 钩子严格来说是一种使用上下文值的方法吗?

2) Is there a recommended way, using React hooks, to update values from the child component, which will then trigger component re-rendering for any components using the useContexthook with this context?

2) 是否有推荐的方法,使用 React 钩子来更新子组件的值,然后使用useContext此上下文的钩子触发任何组件的组件重新渲染?

const ThemeContext = React.createContext({
  style: 'light',
  visible: true
});

function Content() {
  const { style, visible } = React.useContext(ThemeContext);

  const handleClick = () => {
    // change the context values to
    // style: 'dark'
    // visible: false
  }

  return (
    <div>
      <p>
        The theme is <em>{style}</em> and state of visibility is 
        <em> {visible.toString()}</em>
      </p>
      <button onClick={handleClick}>Change Theme</button>
    </div>
  )
};

function App() {
  return <Content />
};

const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.2/umd/react-dom.production.min.js"></script>

回答by Tholle

How to update context with hooks is discussed in the How to avoid passing callbacks down?part of the Hooks FAQ.

如何使用钩子更新上下文在如何避免传递回调?Hooks 常见问题的一部分。

The argument passed to createContextwill only be the default value if the component that uses useContexthas no Providerabove it further up the tree. You could instead create a Providerthat supplies the styleand visibilityas well as functions to toggle them.

createContext如果使用的组件useContext没有Provider在树上进一步向上,则传递给的参数将仅是默认值。您可以改为创建一个Provider提供stylevisibility以及切换它们的功能。

Example

例子

const { createContext, useContext, useState } = React;

const ThemeContext = createContext(null);

function Content() {
  const { style, visible, toggleStyle, toggleVisible } = useContext(
    ThemeContext
  );

  return (
    <div>
      <p>
        The theme is <em>{style}</em> and state of visibility is
        <em> {visible.toString()}</em>
      </p>
      <button onClick={toggleStyle}>Change Theme</button>
      <button onClick={toggleVisible}>Change Visibility</button>
    </div>
  );
}

function App() {
  const [style, setStyle] = useState("light");
  const [visible, setVisible] = useState(true);

  function toggleStyle() {
    setStyle(style => (style === "light" ? "dark" : "light"));
  }
  function toggleVisible() {
    setVisible(visible => !visible);
  }

  return (
    <ThemeContext.Provider
      value={{ style, visible, toggleStyle, toggleVisible }}
    >
      <Content />
    </ThemeContext.Provider>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

回答by mohamed khaled

You can use this approach, no matter how many nested components do you have it will work fine.

您可以使用这种方法,无论您有多少嵌套组件,它都可以正常工作。

// Settings Context - src/context/Settings
import React, { useState } from "react";

const SettingsContext = React.createContext();

const defaultSettings = {
   theme: "light",
};

export const SettingsProvider = ({ children, settings }) => {
   const [currentSettings, setCurrentSettings] = useState(
      settings || defaultSettings
   );

   const saveSettings = (values) => {
     setCurrentSettings(values)
   };

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

export const SettingsConsumer = SettingsContext.Consumer;

export default SettingsContext;
// Settings Hook - src/hooks/useSettings
import { useContext } from "react";
import SettingsContext from "src/context/SettingsContext";

export default () => {
   const context = useContext(SettingsContext);

   return context;
};
// src/index
ReactDOM.render(
   <SettingsProvider settings={settings}>
         <App />
   </SettingsProvider>,
   document.getElementById("root")
// Any component do you want to toggle the theme from
// Example: src/components/Navbar
const { settings, saveSettings } = useSettings();

const handleToggleTheme = () => {
  saveSettings({theme: "light"});
};