Probablemente me esté perdiendo algo muy obvio y me gustaría aclararme.
Aquí está mi comprensión.
En un componente de reacción ingenua, tenemos states
& props
. La actualización state
con setState
vuelve a renderizar todo el componente. props
en su mayoría son 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 un ayudante connect()
que inyecta parte del árbol de estado (que es de interés para el componente) y actionCreators en cuanto props
al componente, generalmente a través de algo como
const TodoListComponent = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
Sin embargo, con el entendimiento de que setState
es esencial para la TodoListComponent
que reaccionan al cambio árbol del estado redux (re-render), no puedo encontrar ninguna state
o setState
código relacionado en el TodoList
archivo del componente. Lee algo como esto:
const TodoList = ({ todos, onTodoClick }) => (
<ul>
{todos.map(todo =>
<Todo
key={todo.id}
{...todo}
onClick={() => onTodoClick(todo.id)}
/>
)}
</ul>
)
¿Alguien puede indicarme la dirección correcta en cuanto a lo que me estoy perdiendo?
PD: Estoy siguiendo el ejemplo de la lista de tareas pendientes incluido con el paquete redux .
fuente
prev.a === current.a && prev.b === current.b && .....
. Eso supone que cualquier cambio de datos dará como resultado nuevas referencias, lo que significa que se requieren actualizaciones de datos inmutables en lugar de una mutación directa.Mi respuesta está un poco fuera de lugar. 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 renderizar, a pesar de que recibió nuevos accesorios.
Los desarrolladores de React tuvieron una respuesta a esta pregunta que se hace a menudo, algo así como que si la (tienda) estaba mutada, el 99% de las veces esa es la razón por la que React no volverá a renderizarse. Sin embargo, nada sobre el otro 1%. La mutación no fue el caso aquí.
TLDR;
Edge Caso: Una vez que
state
las actualizaciones, a continuación, la aplicación no volver a hacer!Resulta que si su aplicación se usa solo
state
para mostrar sus elementos, seprops
puede actualizar, perostate
no lo hará, por lo que no se vuelve a renderizar.Tenía
state
que dependía de loprops
recibido de reduxstore
. Los datos que necesitaba aún no estaban en la tienda, así que los obtuvecomponentDidMount
, como corresponde. Recuperé 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 todavía estaba lleno de cadenas vacías.Un ejemplo de esto es decir que un usuario cargó una página de "editar publicación" desde una URL guardada. Tienes acceso al
postId
desde la URL, pero la informaciónstore
aún no está , así que la obtienes. Los elementos de su página son componentes controlados, por lo que todos los datos que muestra están en formatostate
.Con redux, se obtuvieron los datos, se actualizó la tienda y se editó el componente
connect
, pero la aplicación no reflejó los cambios. En una mirada más cercana,props
se recibieron, pero la aplicación no se actualizó.state
no se actualizó.Bueno,
props
se actualizará y se propagará, perostate
no lo hará. Debe indicar específicamentestate
que se actualice.No puedes hacer esto
render()
ycomponentDidMount
ya terminaste sus ciclos.componentWillReceiveProps
es donde actualiza lasstate
propiedades que dependen de unprop
valor 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 agradecer este artículo que me iluminó sobre la solución que decenas de otras publicaciones, blogs y repositorios no mencionaron. Cualquiera que haya tenido problemas para encontrar una respuesta a este problema evidentemente oscuro, aquí está:
Métodos del ciclo de vida de los componentes de ReactJ: un análisis profundo
fuente
React 16.3
partir de ahora, debes usar el engetDerivedStateFromProps
lugar decomponentWillReceiveProps
. Pero, de hecho, ni siquiera debería hacer todo eso como se articula aquíEsta respuesta es un resumen del artículo de Brian Vaughn titulado Probablemente no necesite un estado derivado (7 de junio de 2018).
Derivar el estado de los accesorios es un anti-patrón en todas sus formas. Incluyendo el uso de la más antigua
componentWillReceiveProps
y la nuevagetDerivedStateFromProps
.En lugar de derivar el estado de los accesorios, considere las siguientes soluciones.
Dos recomendaciones de mejores prácticas
Recomendación 1. Componente totalmente controlado
Recomendación 2. Componente totalmente no controlado con clavefunction EmailInput(props) { return <input onChange={props.onChange} value={props.email} />; }
// 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 cualquier motivo, las recomendaciones no funcionan para su situación.
Alternativa 1: restablecer el componente no controlado con un accesorio de identificación
Alternativa 2: restablecer el componente no controlado con un método de instanciaclass 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; } // ... }
class EmailInput extends Component { state = { email: this.props.defaultEmail }; resetEmailForNewUser(newEmail) { this.setState({ email: newEmail }); } // ... }
fuente
como sé, lo único que hace redux, al cambiar el estado de la tienda es llamar a componentWillRecieveProps si su componente dependía del estado mutado y luego debe forzar a su componente a actualizar, es así
1-store State change-2-call (componentWillRecieveProps (() => {cambio de estado de 3 componentes}))
fuente