reactdom react example reactjs react-context

reactjs - example - react router



Acceder al contexto de reacción fuera de la función de representación (4)

Estoy desarrollando una nueva aplicación usando la nueva API React Context en lugar de Redux, y antes, con Redux , cuando necesitaba obtener una lista de usuarios, por ejemplo, simplemente llamo a componentDidMount mi acción, pero ahora con React Context, mis acciones vivir dentro de mi Consumidor, que está dentro de mi función de representación, lo que significa que cada vez que se llama a mi función de representación, llamará a mi acción para obtener mi lista de usuarios y eso no es bueno porque haré muchas solicitudes innecesarias.

Entonces, ¿cómo puedo llamar solo una vez mi acción, como en componentDidMount en lugar de llamar en render?

Solo para ejemplificar, mira este código:

Supongamos que estoy envolviendo a todos mis Providers en un componente, como este:

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

Luego pongo este componente Proveedor que envuelve toda mi aplicación, así:

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

Ahora, en la vista de mis usuarios, por ejemplo, será algo como esto:

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

Lo que quiero es esto:

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

Pero, por supuesto, el ejemplo anterior no funciona porque los getUsers no viven en mis accesorios de vista de usuarios. ¿Cuál es la forma correcta de hacerlo si esto es posible?


Debe pasar el contexto en el componente principal superior para obtener acceso como accesorios en el elemento secundario.


Ok, encontré una manera de hacer esto con una limitación. Con la biblioteca with-context logré insertar todos mis datos de consumidor en mis accesorios.

Pero, para insertar más de un consumidor en el mismo componente es complicado hacerlo, debe crear consumidores mixtos con esta biblioteca, lo que hace que el código no sea elegante y no sea productivo.

El enlace a esta biblioteca: https://github.com/SunHuawei/with-context

EDITAR: en realidad, no necesita usar la API de contexto múltiple que proporciona with-context , de hecho, puede usar la API simple y hacer un decorador para cada uno de sus contextos y si desea usar más de un consumidor en usted componente, simplemente declara sobre tu clase tantos decoradores como quieras!


Por mi parte, fue suficiente agregar .bind(this) al evento. Así es como se ve mi Componente.

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


EDITAR: con la introducción de react-hooks en v16.8.0 , puede usar el contexto en componentes funcionales haciendo uso de useContext hook

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

EDITAR: desde la versión 16.6.0 en adelante. Puede utilizar el contexto en el método del ciclo de vida utilizando this.context como

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

Antes de la versión 16.6.0, podría hacerlo de la siguiente manera

Para utilizar Context en su método de ciclo de vida, debe escribir su componente como

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

En general, mantendría un contexto en su aplicación y tiene sentido empaquetar el inicio de sesión anterior en un HOC para reutilizarlo. Puedes escribirlo como

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

y luego puedes usarlo como

export default withUserContext(User);