reactjs - que - react js
¿Cómo sabe un componente conectado redux cuándo volver a renderizar? (4)
Probablemente me estoy perdiendo algo muy obvio y me gustaría aclararme.
Aquí está mi entendimiento.
En un componente de reacción ingenua, tenemos
states
y
props
.
El
state
actualización con
setState
vuelve a representar todo el componente.
props
son principalmente de solo lectura y actualizarlos no tiene sentido.
En un componente de reacción que se suscribe a una tienda redux, a través de algo como
store.subscribe(render)
, obviamente se vuelve a renderizar cada vez que se actualiza la tienda.
react-redux
tiene una
connect()
auxiliar
connect()
que inyecta parte del árbol de estado (que es de interés para el componente) y actionCreators como
props
para el componente, generalmente a través de algo como
const TodoListComponent = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
Pero con el entendimiento de que un
setState
es esencial para que
TodoListComponent
reaccione al cambio de árbol de estado redux (re-render), no puedo encontrar ningún
state
o código relacionado con
setState
en el archivo del componente
TodoList
.
Se lee algo como esto:
const TodoList = ({ todos, onTodoClick }) => (
<ul>
{todos.map(todo =>
<Todo
key={todo.id}
{...todo}
onClick={() => onTodoClick(todo.id)}
/>
)}
</ul>
)
¿Puede alguien señalarme en la dirección correcta lo que me estoy perdiendo?
PD: estoy siguiendo el ejemplo de la lista de tareas incluidas con el https://github.com/reactjs/redux/tree/master/examples/todos/src/containers .
Como sé que solo lo que hace Redux, al cambiar el estado de la tienda, se llama a componentWillRecieveProps si su componente dependía del estado mutado y luego debe forzar a su componente a actualizarlo.
1-store State change-2-call (componentWillRecieveProps (() => {cambio de estado de 3 componentes}))
Esta respuesta es un resumen del artículo de Brian Vaughn titulado here (07 de junio de 2018).
Derivar el estado de los accesorios es un antipatrón en todas sus formas.
Incluyendo el uso del
componentWillReceiveProps
anteriorWillReceiveProps y el nuevo
getDerivedStateFromProps
.
En lugar de derivar el estado de los accesorios, considere las siguientes soluciones.
Dos recomendaciones de mejores prácticas.
Recomendación 1. Componente totalmente controladofunction EmailInput(props) {
return <input onChange={props.onChange} value={props.email} />;
}
Recomendación 2. Componente totalmente incontrolado con una llave
// parent class
class EmailInput extends Component {
state = { email: this.props.defaultEmail };
handleChange = event => {
this.setState({ email: event.target.value });
};
render() {
return <input onChange={this.handleChange} value={this.state.email} />;
}
}
// child instance
<EmailInput
defaultEmail={this.props.user.email}
key={this.props.user.id}
/>
Dos alternativas si, por alguna razón, las recomendaciones no funcionan para su situación.
Alternativa 1: restablecer el componente no controlado con un accesorio de identificaciónclass EmailInput extends Component {
state = {
email: this.props.defaultEmail,
prevPropsUserID: this.props.userID
};
static getDerivedStateFromProps(props, state) {
// Any time the current user changes,
// Reset any parts of state that are tied to that user.
// In this simple example, that''s just the email.
if (props.userID !== state.prevPropsUserID) {
return {
prevPropsUserID: props.userID,
email: props.defaultEmail
};
}
return null;
}
// ...
}
Alternativa 2: restablecer componente no controlado con un método de instancia
class EmailInput extends Component {
state = {
email: this.props.defaultEmail
};
resetEmailForNewUser(newEmail) {
this.setState({ email: newEmail });
}
// ...
}
La función de
connect
genera un componente contenedor que se suscribe a la tienda.
Cuando se despacha una acción, se notifica la devolución de llamada del componente contenedor.
Luego ejecuta su función
mapState
y
compara superficialmente
el objeto de resultado de este momento con el objeto de resultado de la última vez (por lo tanto, si
reescribiera
un campo de almacenamiento redux con su mismo valor, no se activaría una nueva representación).
Si los resultados son diferentes, los pasa a su componente "real" como accesorios.
Dan Abramov escribió una excelente versión simplificada de
connect
en (
https://gist.github.com/gaearon/1d19088790e70ac32ea636c025ba424e
) que ilustra la idea básica, aunque no muestra nada del trabajo de optimización.
También tengo enlaces a varios artículos sobre el
rendimiento de Redux
que discuten algunas ideas relacionadas.
actualizar
React-Redux v6.0.0 realizó algunos cambios internos importantes en la forma en que los componentes conectados reciben sus datos de la tienda.
Como parte de eso, escribí una publicación que explica cómo funcionan la API de
connect
y sus componentes internos, y cómo han cambiado con el tiempo:
Idiomatic Redux: la historia y la implementación de React-Redux
Mi respuesta está un poco fuera del campo izquierdo.
Arroja luz sobre un problema que me llevó a esta publicación.
En mi caso, parecía que la aplicación no se estaba volviendo a procesar, a pesar de que recibió nuevos accesorios.
Los desarrolladores de React tenían una respuesta a esta pregunta que a menudo se hacía con la idea de que si la (tienda) estaba mutada, el 99% de las veces esa es la razón por la que reaccionar no se volverá a procesar.
Sin embargo, nada sobre el otro 1%.
La mutación no fue el caso aquí.
TLDR;
componentWillReceiveProps
es cómo se puede mantener elstate
sincronizado con los nuevosprops
.
Edge Case: una vez que el
state
actualiza, ¡la aplicación
se
vuelve a procesar!
Resulta que si su aplicación usa solo el
state
para mostrar sus elementos, los
props
pueden actualizarse, pero el
state
no lo hará, por lo que no se volverá a procesar.
Tenía un
state
que dependía de los
props
recibidos de la
store
redux.
Los datos que necesitaba todavía no estaban en la tienda, así que los obtuve de
componentDidMount
, como es apropiado.
Me devolvieron los accesorios, cuando mi reductor actualizó la tienda, porque mi componente está conectado a través de mapStateToProps.
Pero la página no se procesó y el estado aún estaba lleno de cadenas vacías.
Un ejemplo de esto es decir que un usuario cargó una página "editar publicación" desde una URL guardada.
Tiene acceso al
postId
desde la URL, pero la información aún no está
store
, por lo que debe buscarla.
Los elementos de su página son componentes controlados, por lo que todos los datos que está mostrando están en
state
.
Usando redux, se obtuvieron los datos, se actualizó la tienda y se
connect
el componente, pero la aplicación no reflejó los cambios.
En una mirada más cercana, se recibieron
props
, pero la aplicación no se actualizó.
state
no se actualizó.
Bueno, los
props
se actualizarán y propagarán, pero el
state
no.
Debe indicarle específicamente al
state
que actualice.
No puede hacer esto en
render()
, y
componentDidMount
ya terminó sus ciclos.
componentWillReceiveProps
es donde actualiza
state
propiedades de
state
que dependen de un valor de
prop
modificado.
Ejemplo de uso:
componentWillReceiveProps(nextProps){
if (this.props.post.category !== nextProps.post.category){
this.setState({
title: nextProps.post.title,
body: nextProps.post.body,
category: nextProps.post.category,
})
}
}
Debo dar un agradecimiento a este artículo que me iluminó sobre la solución que docenas de otras publicaciones, blogs y repositorios no mencionaron. Cualquier otra persona que haya tenido problemas para encontrar una respuesta a este problema evidentemente oscuro, aquí está:
Métodos del ciclo de vida del componente ReactJs: una inmersión profunda
componentWillReceiveProps
es donde actualizará elstate
para mantenerse sincronizado con las actualizaciones de losprops
.Una vez que el
state
actualiza, ¡los campos que dependen delstate
vuelven a procesar!