react props prevstate componentwillreceiveprops component actualizar reactjs react-jsx

reactjs - props - setstate prevstate react



¿Se puede obligar a un componente React a volver a reproducir sin llamar a setState? (18)

Tengo un objeto externo (al componente) observable en el que quiero escuchar los cambios. Cuando el objeto se actualiza, emite eventos de cambio, y luego quiero volver a procesar el componente cuando se detecta cualquier cambio.

Con un React.render nivel React.render esto ha sido posible, pero dentro de un componente no funciona (lo cual tiene sentido ya que el método de render solo devuelve un objeto).

Aquí hay un ejemplo de código:

export default class MyComponent extends React.Component { handleButtonClick() { this.render(); } render() { return ( <div> {Math.random()} <button onClick={this.handleButtonClick.bind(this)}> Click me </button> </div> ) } }

Al hacer clic internamente en el botón, se llama this.render() , pero eso no es lo que realmente hace que se produzca la representación (puede ver esto en acción porque el texto creado por {Math.random()} no cambia). Sin embargo, si simplemente llamo this.setState() lugar de this.render() , funciona bien.

Entonces, supongo que mi pregunta es: ¿los componentes React deben tener un estado para volver a reproducir? ¿Hay alguna forma de obligar al componente a actualizarse bajo demanda sin cambiar el estado?


Entonces, supongo que mi pregunta es: ¿los componentes React deben tener un estado para volver a reproducir? ¿Hay alguna forma de obligar al componente a actualizarse bajo demanda sin cambiar el estado?

Las otras respuestas han tratado de ilustrar cómo podrías hacerlo, pero el punto es que no deberías . Incluso la solución hacky de cambiar la clave pierde el punto. El poder de React es ceder el control de administrar manualmente cuándo algo debería renderizarse, y en cambio solo preocuparse por cómo algo debería mapearse en las entradas. Luego suministrar flujo de entradas.

Si necesita forzar manualmente el re-renderizado, seguramente no está haciendo algo bien.


Vincula los cambios de la tienda usando HOC

Usando el patrón HOC (componente de orden superior) , puede envolver sus componentes React y tener actualizaciones automáticas cuando cambien sus tiendas. Este es un enfoque muy ligero sin un marco.

withStores HOC maneja las actualizaciones de la tienda

import React, { Component } from ''react'' export default function(/* store1, store2, store3... */) { const storeArgs = Array.prototype.slice.call(arguments) return function(WrappedComponent) { return class WithStore extends Component { constructor(props) { super(props) this.state = { lastUpdated: Date.now() } this.stores = storeArgs } _onChange = () => { this.setState({ lastUpdated: Date.now() }) } componentWillMount = () => { this.stores && this.stores.forEach(store => { // each store has a common change event to subscribe to store.on(''change'', this._onChange) }) } componentWillUnmount = () => { this.stores && this.stores.forEach(store => { store.off(''change'', this._onChange) }) } render() { return <WrappedComponent lastUpdated={this.state.lastUpdated} {...this.props} /> } } } }

Cómo utilizar

import React, { Component } from ''react'' import { View, Text, Button } from ''react-native'' import withStores from ''./withStores'' import userStore from ''./stores/users'' class MyView { _increaseUserCount = () => { userStore.setState({ userCount: userStore.state.count + 1 }) } render() { return ( <View> <Text>User count: {userStore.state.count}</Text> <Button title="Increase User Count" onPress={this._increaseUserCount} /> </View> ) } } return withStores(userStore)(MyView)

Ejemplo de clase de tienda simple

var ee = require(''event-emitter'') export default class Store { constructor() { this._state = {} this._eventEmitter = ee({}) } get state() { return this._state } setState(newState) { this._state = {...this._state, ...newState} this._eventEmitter.emit(''change'') } on(ev, fn) { this._eventEmitter.on(ev, fn) } off(ev, fn) { this._eventEmitter.off(ev, fn) } }

Almacenar instancia como singleton

import Store from ''./Store'' const myStore = new Store() export default myStore

Esto realmente está destinado a proyectos más pequeños con árboles de baja profundidad de componentes. La razón es que si usa esto para un árbol de componentes más grande, esto no es muy selectivo sobre qué partes actualizar para una tienda, solo la tienda en sí activa la actualización.

Estará bien si divide sus tiendas de una manera más granular, pero una vez más, esta es la razón por la cual redux es bueno, ya que puede ser granular según sea necesario y solo requiere una sola tienda, pero también tiene un diseño desproporcionado en un proyecto más pequeño.


forceUpdate haciendo lo siguiente

CAMINO INCORRECTO : no utilice el índice como clave

this.state.rows.map((item, index) => <MyComponent cell={item} key={index} /> )

MANERA CORRECTA : Use la identificación de datos como clave, puede ser una guía, etc.

this.state.rows.map((item) => <MyComponent item={item} key={item.id} /> )

así que al hacer tal mejora de código, su componente será ÚNICO y se renderizará naturalmente


Cuando desee que se comuniquen dos componentes React, que no están vinculados por una relación (padre-hijo), es recomendable utilizar Flux o arquitecturas similares.

Lo que desea hacer es escuchar los cambios del almacén de componentes observables , que contiene el modelo y su interfaz, y guardar los datos que provocan que el render cambie como state en MyComponent . Cuando la tienda envía los nuevos datos, cambia el estado de su componente, lo que activa automáticamente el renderizado.

Normalmente debe intentar evitar usar forceUpdate() . De la documentación:

Normalmente, debe intentar evitar todos los usos de forceUpdate () y solo leer de this.props y this.state en render (). Esto hace que su aplicación sea mucho más simple y eficiente


ES6 - Incluyo un ejemplo que me fue útil:

En una "instrucción if corta" puede pasar una función vacía como esta:

isReady ? ()=>{} : onClick

Este parece ser el enfoque más corto.

()=>{}


En realidad, forceUpdate() es la única solución correcta ya que setState() podría no desencadenar una nueva representación si se implementa una lógica adicional en shouldComponentUpdate() o cuando simplemente devuelve false .

forceUpdate ()

Llamar a forceUpdate() hará que se forceUpdate() render() en el componente, omitiendo shouldComponentUpdate() . forceUpdate()

setState ()

setState() siempre activará una nueva representación a menos que se implemente una lógica de representación condicional en shouldComponentUpdate() . more...

forceUpdate() puede forceUpdate() desde su componente mediante this.forceUpdate()



Hay algunas formas de volver a procesar su componente:

La solución más simple es usar el método forceUpdate ():

this.forceUpdate()

Una solución más es crear una clave no utilizada en el estado (nonUsedKey) y llamar a la función setState con la actualización de esta nonUsedKey:

this.setState({ nonUsedKey: Date.now() } );

O reescribir todo el estado actual:

this.setState(this.state);

El cambio de utilería también proporciona la recuperación de componentes.


He encontrado que es mejor evitar forceUpdate (). Una forma de forzar el re-render es agregar dependencia de render () en una variable externa temporal y cambiar el valor de esa variable cuando sea necesario.

Aquí hay un ejemplo de código:

class Example extends Component{ constructor(props){ this.state = {temp:0}; this.forceChange = this.forceChange.bind(this); } forceChange(){ this.setState(prevState => ({ temp: prevState.temp++ })); } render(){ return( <div>{this.state.temp && <div> ... add code here ... </div>} </div> ) } }

Llame this.forceChange () cuando necesite forzar el renderizado.


Otra forma es llamar a setState , Y preservar el estado:

this.setState(prevState=>({...prevState}));


Para lograr lo que está describiendo, intente this.forceUpdate ().


Podemos usar this.forceUpdate () como se muestra a continuación.

class MyComponent extends React.Component { handleButtonClick = ()=>{ this.forceUpdate(); } render() { return ( <div> {Math.random()} <button onClick={this.handleButtonClick}> Click me </button> </div> ) } } ReactDOM.render(<MyComponent /> , mountNode);

La parte Elemento ''Math.random'' en el DOM solo se actualiza incluso si usa setState para volver a representar el componente.

Todas las respuestas aquí son correctas, complementando la pregunta para la comprensión ... ya que sabemos que volver a representar un componente sin usar setState ({}) es usando forceUpdate ().

El código anterior se ejecuta con setState como se muestra a continuación.

class MyComponent extends React.Component { handleButtonClick = ()=>{ this.setState({ }); } render() { return ( <div> {Math.random()} <button onClick={this.handleButtonClick}> Click me </button> </div> ) } } ReactDOM.render(<MyComponent /> , mountNode);


Podrías hacerlo de dos maneras:

1. Use el método forceUpdate() :

Hay algunos problemas forceUpdate() que pueden ocurrir al usar el método forceUpdate() . Un ejemplo es que ignora el método shouldComponentUpdate() y volverá a representar la vista independientemente de si shouldComponentUpdate() devuelve falso. Debido a esto, se debe evitar usar forceUpdate () cuando sea posible.

2. Pasar this.state al método setState()

La siguiente línea de código supera el problema con el ejemplo anterior:

this.setState(this.state);

Realmente todo lo que está haciendo es sobrescribir el estado actual con el estado actual que desencadena una nueva representación. Aún así, esta no es necesariamente la mejor manera de hacer las cosas, pero supera algunos de los problemas técnicos que puede encontrar utilizando el método forceUpdate ().


Puede usar forceUpdate () para ver más detalles ( forceUpdate() ).


Solo otra respuesta para respaldar la respuesta aceptada :-)

React desalienta el uso de forceUpdate() porque generalmente tienen un enfoque muy "esta es la única forma de hacerlo" hacia la programación funcional. Esto está bien en muchos casos, pero muchos desarrolladores de React vienen con un fondo OO, y con ese enfoque, está perfectamente bien escuchar un objeto observable.

Y si lo hace, probablemente sepa que DEBE volver a renderizar cuando el "fuego" observable, y como tal, DEBERÍA usar forceUpdate() y en realidad es un plus que shouldComponentUpdate() NO está involucrado aquí.

Herramientas como MobX, que adopta un enfoque OO, en realidad está haciendo esto debajo de la superficie (en realidad, MobX llama render() directamente)


forceUpdate (), pero cada vez que escuché a alguien hablar sobre eso, se le ha seguido y nunca debe usar esto.


forceUpdate(); el método funcionará pero es recomendable usar setState();


forceUpdate debe evitarse porque se desvía de una mentalidad React. Los documentos de React citan un ejemplo de cuándo forceUpdate podría usarse:

Por defecto, cuando el estado o los accesorios de su componente cambian, su componente se volverá a representar. Sin embargo, si estos cambian implícitamente (por ejemplo: los datos profundos dentro de un objeto cambian sin cambiar el objeto mismo) o si su método render () depende de otros datos, puede decirle a React que necesita volver a ejecutar render () llamando forceUpdate ().

Sin embargo, me gustaría proponer la idea de que incluso con objetos profundamente anidados, forceUpdate es innecesario. Al usar una fuente de datos inmutable, los cambios de seguimiento se vuelven baratos; un cambio siempre dará como resultado un nuevo objeto, por lo que solo necesitamos verificar si la referencia al objeto ha cambiado. Puede usar la biblioteca Immutable JS para implementar objetos de datos inmutables en su aplicación.

Normalmente, debe intentar evitar todos los usos de forceUpdate () y solo leer de this.props y this.state en render (). Esto hace que su componente sea "puro" y que su aplicación sea mucho más simple y eficiente. forceUpdate()

Cambiar la clave del elemento que desea volver a representar funcionará. Establezca la clave de apoyo en su elemento a través del estado y luego cuando desee actualizar el estado establecido para tener una nueva clave.

<Element key={this.state.key} />

Luego se produce un cambio y restablece la clave

this.setState({ key: Math.random() });

Quiero señalar que esto reemplazará el elemento en el que está cambiando la clave. Un ejemplo de dónde esto podría ser útil es cuando tiene un campo de entrada de archivo que desea restablecer después de cargar una imagen.

Si bien la verdadera respuesta a la pregunta del OP sería forceUpdate() , he encontrado esta solución útil en diferentes situaciones. También quiero señalar que si te encuentras usando forceUpdate es posible que desees revisar tu código y ver si hay otra forma de hacer las cosas.

NOTA 1-9-2019:

Lo anterior (cambiando la clave) reemplazará completamente el elemento. Si te encuentras actualizando la clave para que los cambios sucedan, probablemente tengas un problema en otro lugar de tu código. Usar Math.random() en clave volverá a crear el elemento con cada render. NO recomendaría actualizar la clave de esta manera, ya que react utiliza la clave para determinar la mejor manera de volver a representar las cosas.