在渲染函数之外访问React Context

Gus*_*nça 61 reactjs react-context

我正在使用新的React Context API而不是Redux开发一个新的应用程序,之前,Redux当我需要获取用户列表时,我只需调用componentDidMount我的操作,但现在使用React Context,我的操作就在里面我的消费者在我的渲染函数中,这意味着每次调用我的渲染函数时,它都会调用我的动作来获取我的用户列表,这是不好的,因为我会做很多不必要的请求.

那么,我怎么只能调用一次我的动作,比如componentDidMount不是在渲染中调用?

举个例子,看看这段代码:

让我们假设我将所有内容包装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>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

然后我把这个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>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,在我的用户视图中,它将是这样的:

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>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

我想要的是这个:

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>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

但是当然上面的例子不起作用,因为getUsers不住在我的用户视图道具中.如果可以的话,这样做的正确方法是什么?

Shu*_*tri 96

编辑:通过在v16.8.0中引入react-hooks ,您可以通过使用useContext钩子在功能组件中使用上下文

const Users = () => {
    const contextValue = useContext(UserContext);
    // rest logic here
}
Run Code Online (Sandbox Code Playgroud)

编辑:从版本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
Run Code Online (Sandbox Code Playgroud)

在版本16.6.0之前,您可以通过以下方式执行此操作

为了在你的lifecyle方法中使用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>
)
Run Code Online (Sandbox Code Playgroud)

通常,您将在App中维护一个上下文,将上述登录包装在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>
    );
  };
};
Run Code Online (Sandbox Code Playgroud)

然后你可以像使用它一样

export default withUserContext(User);
Run Code Online (Sandbox Code Playgroud)

  • 这是一种方法!但我用其他东西包装我的组件,因此这样做代码会变得越来越复杂。因此,使用 with-context 库及其装饰器使代码变得更加简单。不过还是谢谢你的回答! (2认同)