监听消费者组件中的 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>;
};
我在我的项目中使用 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>;
};