监听消费者组件中的 ReactContext 变量变化

Listening for ReactContext variable changes in consumer component

我在我的项目中使用 ReactContext,这里我有一个使用一些上下文变量的 'consumer' 组件。一切正常,除非我尝试 'listen' 更改变量 'myName'.

<MyContext.Consumer>
      {context => {
        return (
          <div>Hello, {context.myName}, your title is age {...}</div>
        )
      }}
</MyContext.Consumer>

每当变量 'myName' 发生变化时,我想进行 ajax 调用,获取一些数据(如年龄)并将其显示在组件中。我一直在寻找一种方法来监听 'myName' 的变化,最好的方法是什么?我注意到虽然该组件反映了最新的 'myName',但当 myName 更改时会调用 none 的 React 生命周期方法。

您需要在 class (docs) 中添加 contextType 属性。然后您可以在生命周期方法中访问更新的上下文。我已经从文档中更改了一个示例来展示这一点。请参阅 ThemedButton 组件。您可以注释掉 static contextType 并注意到该组件没有收到上下文。

const ThemeContext = React.createContext("light");

class App extends React.Component {
  state = {
    theme: "dark"
  };

  render() {
    // Use a Provider to pass the current theme to the tree below.
    // Any component can read it, no matter how deep it is.
    // In this example, we're passing "dark" as the current value.
    return (
      <ThemeContext.Provider value={this.state.theme}>
        <button
          onClick={() => {
            this.state.theme === "dark"
              ? this.setState({ theme: "light" })
              : this.setState({ theme: "dark" });
          }}
        >
          Change theme
        </button>
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// A component in the middle doesn't have to
// pass the theme down explicitly anymore.
function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // Assign a contextType to read the current theme context.
  // React will find the closest theme Provider above and use its value.
  // In this example, the current theme is "dark".
  static contextType = ThemeContext;

  componentDidUpdate() {
    console.log("Update", this.context);
  }

  render() {
    return <div>{JSON.stringify(this.context)}</div>;
  }
}

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

如果您没有可用的 public class 字段语法,您可以使用 ThemedButton.contextType = ThemeContext.

的类似版本

如果您只是以某种方式组合您的组件,例如将当前上下文作为 props 传递给执行提取的组件,您也可以使用 React 生命周期方法。

这是一个带有 React hooks 实现的简短虚拟示例 CodeSandbox -example

这个例子的要点,

// Initialize context
const context = React.createContext({ name: "" });

/**
 * My provider component which has it's own state
 * for updating existing context.
 */
const MyProvider = ({ children }) => {
  const [state, setState] = React.useState({ name: "" });
  return (
    <context.Provider value={state}>
      <input
        value={state.name}
        onChange={({ target }) => {
          console.log(target.value);
          setState({ name: target.value });
        }}
      />
      {children}
    </context.Provider>
  );
};



/**
 * Context to consume existing parent component context
 */
const MyConsumer = ({ children }) => {
  return <context.Consumer>{ctx => <MyComponent {...ctx} />}</context.Consumer>;
};

/**
 * provide values as props to your component with lifecycle-methods.
 */
const MyComponent = ({ name }) => {
  const [fetchResult, setResult] = React.useState({});
  React.useEffect(() => {
    console.log("child updated with name: ", name);
    /**
     * Fetch some data and set it to local state
     */
    const mockFetchResult = {
      title: name + `\n${Math.random() * 1024}` // Dummy example to get some random data
    };
    setResult(mockFetchResult);
  }, [name]);
  return <p>{fetchResult.title}</p>;
};