o01
Digamos que tengo un componente de vista que tiene una representación condicional:
render(){
if (this.state.employed) {
return (
<div>
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
MyInput se parece a esto:
class MyInput extends React.Component {
...
render(){
return (
<div>
<input name={this.props.name}
ref="input"
type="text"
value={this.props.value || null}
onBlur={this.handleBlur.bind(this)}
onChange={this.handleTyping.bind(this)} />
</div>
);
}
}
Digamos employed
es verdad. Cada vez que lo cambio a falso y la otra vista se procesa, solo unemployment-duration
se reinicializa. También unemployment-reason
se precarga con el valor de job-title
(si se dio un valor antes de que cambiara la condición).
Si cambio el marcado en la segunda rutina de renderizado a algo como esto:
render(){
if (this.state.employed) {
return (
<div>
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<span>Diff me!</span>
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
Parece que todo funciona bien. Parece que React simplemente no logra diferenciar ‘puesto de trabajo’ y ‘razón de desempleo’.
Por favor dime que estoy haciendo mal…
alex k
Cambia la clave del componente.
<Component key="1" />
<Component key="2" />
El componente se desmontará y se montará una nueva instancia de Componente ya que la clave ha cambiado.
editar: Documentado en Probablemente no necesite un estado derivado:
Cuando cambia una clave, React creará una nueva instancia de componente en lugar de actualizar la actual. Las claves generalmente se usan para listas dinámicas, pero también son útiles aquí.
-
Esto debería ser mucho más obvio en la documentación de React. Esto logró exactamente lo que buscaba, pero me tomó horas encontrarlo.
– Pablo
22 de abril de 2018 a las 23:54
-
Bueno, esto me ayudó mucho! ¡Gracias! Necesitaba restablecer una animación CSS, pero la única forma de hacerlo es forzar una nueva representación. Estoy de acuerdo en que esto debería ser más obvio en la documentación de reacción.
– Alex. PAGS.
26 de julio de 2018 a las 19:43
-
@Alex.P. ¡Agradable! Las animaciones CSS pueden ser complicadas a veces. Me interesaría ver un ejemplo.
– Alex K.
27 de julio de 2018 a las 21:04
-
Documentación de React que describe esta técnica: reactjs.org/blog/2018/06/07/…
– GameSalutes
20 de enero de 2019 a las 21:38
-
Gracias. Estoy muy agradecido por esto. Intenté alimentar números aleatorios a accesorios no declarados como “randomNumber”, pero el único accesorio que funcionó fue la clave.
– Vergüenza
13 de junio de 2019 a las 1:47
cris
Lo que probablemente sucede es que React piensa que solo uno MyInput
(unemployment-duration
) se agrega entre los renders. Como tal, el job-title
nunca es reemplazado por el unemployment-reason
que también es la razón por la que se intercambian los valores predefinidos.
Cuando React hace la diferencia, determinará qué componentes son nuevos y cuáles son antiguos en función de su key
propiedad. Si no se proporciona dicha clave en el código, generará la suya propia.
La razón por la que funciona el último fragmento de código que proporciona es porque React esencialmente necesita cambiar la jerarquía de todos los elementos bajo el padre. div
y creo que eso desencadenaría una nueva representación de todos los niños (por eso funciona). ¿Habías agregado el span
hacia abajo en lugar de hacia arriba, la jerarquía de los elementos anteriores no cambiaría y esos elementos no se volverían a representar (y el problema persistiría).
Esto es lo que el oficial Reaccionar documentación dice:
La situación se vuelve más complicada cuando los elementos secundarios se mezclan (como en los resultados de búsqueda) o si se agregan nuevos componentes al principio de la lista (como en los flujos). En estos casos en los que la identidad y el estado de cada elemento secundario deben mantenerse en los pases de procesamiento, puede identificar de forma única a cada elemento secundario asignándole una clave.
Cuando React reconcilie a los niños con llave, se asegurará de que cualquier niño con llave sea reordenado (en lugar de aplastado) o destruido (en lugar de reutilizado).
Debería poder solucionar esto proporcionando un único key
elemento usted mismo a cualquiera de los padres div
o a todos MyInput
elementos.
Por ejemplo:
render(){
if (this.state.employed) {
return (
<div key="employed">
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div key="notEmployed">
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
O
render(){
if (this.state.employed) {
return (
<div>
<MyInput key="title" ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<MyInput key="reason" ref="unemployment-reason" name="unemployment-reason" />
<MyInput key="duration" ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
Ahora, cuando React haga la diferencia, verá que el divs
son diferentes y lo volverán a renderizar incluyendo todos sus hijos (primer ejemplo). En el segundo ejemplo, la diferencia será un éxito en job-title
y unemployment-reason
ya que ahora tienen claves diferentes.
Por supuesto, puede usar las claves que desee, siempre que sean únicas.
Actualización Agosto 2017
Para una mejor comprensión de cómo funcionan las claves en React, recomiendo leer mi respuesta a Comprender las claves únicas en React.js.
Actualización noviembre 2017
Esta actualización debería haberse publicado hace un tiempo, pero al usar literales de cadena en ref
ahora está en desuso. Por ejemplo ref="job-title"
ahora debería ser ref={(el) => this.jobTitleRef = el}
(por ejemplo). Consulte mi respuesta a la advertencia de desuso usando this.refs para obtener más información.
-
it will determine which components are new and which are old based on their key property.
– eso fue… clave… para mi entendimiento– Larry
17 de noviembre de 2016 a las 12:02
-
Muchas gracias ! También me di cuenta de que todos los componentes secundarios de un mapa se volvieron a renderizar con éxito y no podía entender por qué.
– Valentin Voilean
29 de noviembre de 2016 a las 13:07
-
¡una buena sugerencia es usar una variable de estado (que cambia, como una identificación, por ejemplo) como la clave para el div!
– Macilias
8 de mayo de 2019 a las 14:06
Usar setState
en su opinión para cambiar employed
propiedad del estado. Este es un ejemplo del motor de renderizado React.
someFunctionWhichChangeParamEmployed(isEmployed) {
this.setState({
employed: isEmployed
});
}
getInitialState() {
return {
employed: true
}
},
render(){
if (this.state.employed) {
return (
<div>
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<span>Diff me!</span>
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
-
Ya estoy haciendo esto. La variable ’empleada’ es parte del estado de los componentes de la vista y se cambia a través de su función setState. Lo siento por no explicar eso.
– o01
4 de marzo de 2016 a las 9:40
-
La variable ’empleada’ debe ser propiedad del estado React. No es obvio en su ejemplo de código.
– Dmitriy
4 de marzo de 2016 a las 9:41
-
¿Cómo se cambia este.estado.empleado? Muestra el código, por favor. ¿Está seguro de que usa setState en el lugar adecuado en su código?
– Dmitriy
4 de marzo de 2016 a las 9:45
-
El componente de vista es un poco más complejo de lo que muestra mi ejemplo. Además de los componentes MyInput, también representa un grupo de botones de opción que controla el valor de ’empleado’ con un controlador onChange. En el controlador onChange, configuro el estado del componente de vista en consecuencia. La vista vuelve a renderizarse bien cuando cambia el valor del grupo de botones de opción, pero React cree que el primer componente MyInput es el mismo que antes de que ’empleado’ cambiara.
– o01
4 de marzo de 2016 a las 9:51
Estoy trabajando en Crud para mi aplicación. Así es como lo hice Obtuve Reactstrap como mi dependencia.
import React, { useState, setState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import firebase from 'firebase';
// import { LifeCrud } from '../CRUD/Crud';
import { Row, Card, Col, Button } from 'reactstrap';
import InsuranceActionInput from '../CRUD/InsuranceActionInput';
const LifeActionCreate = () => {
let [newLifeActionLabel, setNewLifeActionLabel] = React.useState();
const onCreate = e => {
const db = firebase.firestore();
db.collection('actions').add({
label: newLifeActionLabel
});
alert('New Life Insurance Added');
setNewLifeActionLabel('');
};
return (
<Card style={{ padding: '15px' }}>
<form onSubmit={onCreate}>
<label>Name</label>
<input
value={newLifeActionLabel}
onChange={e => {
setNewLifeActionLabel(e.target.value);
}}
placeholder={'Name'}
/>
<Button onClick={onCreate}>Create</Button>
</form>
</Card>
);
};
Algunos React Hooks allí
¿Cuál es el
data-reactid
en cada uno de losMyInput
(oinput
como se ve en DOM) elementos antes y después de laemployed
¿cambiar?– Chris
4 de marzo de 2016 a las 9:46
@Chris No pude especificar que el componente MyInput representa la entrada envuelta en un
<div>
. losdata-reactid
los atributos parecen ser diferentes tanto en el div de envoltura como en el campo de entrada.job-title
la entrada obtiene la identificacióndata-reactid=".0.1.1.0.1.0.1"
tiempounemployment-reason
la entrada obtiene la identificacióndata-reactid=".0.1.1.0.1.2.1"
– o01
4 de marzo de 2016 a las 9:58
y que hay con
unemployment-duration
?– Chris
4 de marzo de 2016 a las 9:59
@Chris Lo siento, hablé demasiado pronto. En el primer ejemplo (sin el lapso “diff me”), el
reactid
los atributos son idénticos enjob-title
yunemployment-reason
mientras que en el segundo ejemplo (con el diff span) son diferentes.– o01
4 de marzo de 2016 a las 10:01
@Chris para
unemployment-duration
lareactid
El atributo es siempre único.– o01
4 de marzo de 2016 a las 10:04