reactjs 在渲染函数之外访问 React Context
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/49809884/
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
Access React Context outside of render function
提问by Gustavo Mendon?a
I am developing a new app using the new React Context API instead of Redux, and before, with Redux, when I needed to get a list of users for example, I simply call in componentDidMountmy action, but now with React Context, my actions live inside my Consumer which is inside my render function, which means that every time my render function is called, it will call my action to get my users list and that is not good because I will be doing a lot of unecessary requests.
我正在使用新的 React Context API 而不是 Redux 开发一个新的应用程序,之前,Redux当我需要获取用户列表时,例如,我只需调用componentDidMount我的操作,但现在使用 React Context,我的操作就在里面我的消费者在我的渲染函数中,这意味着每次调用我的渲染函数时,它都会调用我的操作来获取我的用户列表,这并不好,因为我会做很多不必要的请求。
So, how I can call only one time my action, like in componentDidMountinstead of calling in render?
那么,我如何才能只调用一次我的动作,比如componentDidMount调用而不是调用渲染?
Just to exemplify, look at this code:
只是为了举例,看看这段代码:
Let's suppose that I am wrapping all my Providersin one component, like this:
假设我将所有内容都包装Providers在一个组件中,如下所示:
import React from 'react';
import UserProvider from './UserProvider';
import PostProvider from './PostProvider';
export default class Provider extends React.Component {
render(){
return(
<UserProvider>
<PostProvider>
{this.props.children}
</PostProvider>
</UserProvider>
)
}
}
Then I put this Provider component wrapping all my app, like this:
然后我把这个 Provider 组件包装了我所有的应用程序,就像这样:
import React from 'react';
import Provider from './providers/Provider';
import { Router } from './Router';
export default class App extends React.Component {
render() {
const Component = Router();
return(
<Provider>
<Component />
</Provider>
)
}
}
Now, at my users view for example, it will be something like this:
现在,以我的用户视图为例,它将是这样的:
import React from 'react';
import UserContext from '../contexts/UserContext';
export default class Users extends React.Component {
render(){
return(
<UserContext.Consumer>
{({getUsers, users}) => {
getUsers();
return(
<h1>Users</h1>
<ul>
{users.map(user) => (
<li>{user.name}</li>
)}
</ul>
)
}}
</UserContext.Consumer>
)
}
}
What I want is this:
我想要的是这个:
import React from 'react';
import UserContext from '../contexts/UserContext';
export default class Users extends React.Component {
componentDidMount(){
this.props.getUsers();
}
render(){
return(
<UserContext.Consumer>
{({users}) => {
getUsers();
return(
<h1>Users</h1>
<ul>
{users.map(user) => (
<li>{user.name}</li>
)}
</ul>
)
}}
</UserContext.Consumer>
)
}
}
But ofcourse that the example above don't work because the getUsersdon't live in my Users view props. What is the right way to do it if this is possible at all?
但是当然上面的例子不起作用,因为getUsers它不在我的用户视图中。如果可能的话,正确的方法是什么?
回答by Shubham Khatri
EDIT:With the introduction of react-hooks in v16.8.0, you can use context in functional components by making use of useContexthook
编辑:随着v16.8.0中 react-hooks 的引入,您可以通过使用useContexthook在功能组件中使用上下文
const Users = () => {
const contextValue = useContext(UserContext);
// rest logic here
}
EDIT:From version 16.6.0onwards. You can make use of context in lifecycle method using this.contextlike
编辑:从16.6.0版开始。您可以使用this.context像在生命周期方法中使用上下文
class Users extends React.Component {
componentDidMount() {
let value = this.context;
/* perform a side-effect at mount using the value of UserContext */
}
componentDidUpdate() {
let value = this.context;
/* ... */
}
componentWillUnmount() {
let value = this.context;
/* ... */
}
render() {
let value = this.context;
/* render something based on the value of UserContext */
}
}
Users.contextType = UserContext; // This part is important to access context values
Prior to version 16.6.0, you could do it in the following manner
在 16.6.0 版本之前,您可以通过以下方式进行
In order to use Context in your lifecyle method, you would write your component like
为了在你的生命周期方法中使用 Context,你可以像这样编写你的组件
class Users extends React.Component {
componentDidMount(){
this.props.getUsers();
}
render(){
const { users } = this.props;
return(
<h1>Users</h1>
<ul>
{users.map(user) => (
<li>{user.name}</li>
)}
</ul>
)
}
}
export default props => ( <UserContext.Consumer>
{({users, getUsers}) => {
return <Users {...props} users={users} getUsers={getUsers} />
}}
</UserContext.Consumer>
)
Generally you would maintain one context in your App and it makes sense to package the above login in an HOC so as to reuse it. You can write it like
通常,您会在您的应用程序中维护一个上下文,并且将上述登录名打包在 HOC 中以便重用它是有意义的。你可以这样写
import UserContext from 'path/to/UserContext';
const withUserContext = Component => {
return props => {
return (
<UserContext.Consumer>
{({users, getUsers}) => {
return <Component {...props} users={users} getUsers={getUsers} />;
}}
</UserContext.Consumer>
);
};
};
and then you can use it like
然后你可以像这样使用它
export default withUserContext(User);
回答by Gustavo Mendon?a
Ok, I found a way to do this with a limitation. With the with-contextlibrary I managed to insert all my consumer data into my component props.
好的,我找到了一种有限制的方法。使用该with-context库,我设法将所有消费者数据插入到我的组件道具中。
But, to insert more than one consumer into the same component is complicated to do, you have to create mixed consumers with this library, which makes not elegant the code and non productive.
但是,在同一个组件中插入多个消费者是很复杂的,你必须用这个库创建混合消费者,这使得代码不优雅并且没有生产力。
The link to this library: https://github.com/SunHuawei/with-context
该库的链接:https: //github.com/SunHuawei/with-context
EDIT: Actually you don't need to use the multi context api that with-contextprovide, in fact, you can use the simple api and make a decorator for each of your context and if you want to use more than one consumer in you component, just declare above your class as much decorators as you want!
编辑:实际上,您不需要使用提供的多上下文 api,with-context事实上,您可以使用简单的 api 并为您的每个上下文制作一个装饰器,如果您想在组件中使用多个消费者,只需在你的类上面声明你想要的装饰器!
回答by Ballpin
For my part it was enough to add .bind(this)to the event. This is how my Component looks like.
就我而言,添加.bind(this)到活动中就足够了。这就是我的组件的样子。
// Stores File
class RootStore {
//...States, etc
}
const myRootContext = React.createContext(new RootStore())
export default myRootContext;
// In Component
class MyComp extends Component {
static contextType = myRootContext;
doSomething() {
console.log()
}
render() {
return <button onClick={this.doSomething.bind(this)}></button>
}
}
回答by kprocks
You have to pass context in higher parent component to get access as a props in child.
您必须在更高的父组件中传递上下文才能作为子组件中的道具获得访问权限。

