111 votes

Accéder au contexte React en dehors de la fonction de rendu

Je suis en train d'élaborer une nouvelle application à l'aide de la nouvelle Réagir Contexte de l'API au lieu de Redux, et avant, avec Redux, quand j'en avais besoin pour obtenir une liste des utilisateurs, par exemple, j'ai simplement appeler en componentDidMount de mon action, mais maintenant, avec Réagissent Contexte, mes actions vivre à l'intérieur de ma Consommation qui est à l'intérieur de ma fonction rendu, ce qui signifie que chaque fois que mon render fonction est appelée, il va appeler mon action pour obtenir ma liste des utilisateurs et qui n'est pas bien parce que je vais faire beaucoup d'élément de la demande.

Donc, comment je peux l'appeler qu'une seule fois mon action, comme en componentDidMount au lieu de faire appel à rendre?

Juste pour donner un exemple, regardez ce code:

Supposons que je termine tous mes Providers dans un composant, comme ceci:

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>
    )
  }
}

Ensuite j'ai mis ce composant Fournisseur de emballage de tous mes app, comme ceci:

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>
    )
  }
}

Maintenant, à mon aux utilisateurs d'afficher, par exemple, il sera quelque chose comme ceci:

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>
    )
  }
}

Ce que je veux, c'est ceci:

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>
    )
  }
}

Mais bien sûr que l'exemple ci-dessus ne fonctionnent pas parce que l' getUsers ne vivent pas dans mes Utilisateurs propriétés de la vue. Quelle est la bonne façon de le faire si cela est possible?

164voto

Shubham Khatri Points 67350

EDIT: Avec l'introduction de réagir crochets en v16.8.0, vous pouvez utiliser le contexte de composants fonctionnels en faisant usage de l' useContext crochet

const Users = () => {
    const contextValue = useContext(UserContext);
    // rest logic here
}

EDIT: Depuis la version 16.6.0 partir. Vous pouvez faire usage de contexte dans le cycle de vie de la méthode à l'aide d' this.context comme

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

Avant la version 16.6.0, vous pouvez procéder de la façon suivante

Afin de les utiliser dans vos lifecyle méthode, vous devez écrire votre composant comme

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>
)

Généralement, vous permettrait de maintenir un contexte de votre Application et il est logique de paquet au-dessus de la connexion dans un HOC afin de la réutiliser. Vous pouvez l'écrire comme

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>
    );
  };
};

et puis vous pouvez l'utiliser comme

export default withUserContext(User);

3voto

Gustavo Mendonça Points 1036

Ok, j'ai trouvé un moyen de faire cela avec une limitation. Avec l' with-context bibliothèque, j'ai réussi à insérer toutes mes données de consommation dans mon composant d'accessoires.

Mais, d'insérer plus d'un consommateur, dans le même composant est compliqué à faire, vous devez créer des consommateurs avec cette bibliothèque, ce qui le rend pas très élégant le code et non productif.

Le lien vers cette bibliothèque: https://github.com/SunHuawei/with-context

EDIT: en Fait vous n'avez pas besoin d'utiliser le multi contexte d'api, with-context fournir, en fait, vous pouvez utiliser l'api simple et de faire un décorateur pour chaque contexte et si vous voulez utiliser plus d'un consommateur, en vous composant, il suffit de déclarer au-dessus de votre classe comme beaucoup de décorateurs comme vous voulez!

0voto

Ballpin Points 36

Pour ma part, il suffisait d'ajouter .bind(this) à l'événement. Voici à quoi ressemble mon composant.

 // 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>
  }
}
 

-14voto

kprocks Points 21

Vous devez passer le contexte dans le composant parent supérieur pour obtenir l'accès en tant qu'accessoire dans l'enfant.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X