reactjs - helmet - react meta tags
Actualización del estado en el cambio de accesorios en el Formulario de reacción (9)
Tengo problemas con un formulario React y con la administración adecuada del estado.
Tengo un campo de entrada de tiempo en un formulario (en un modal).
El valor inicial se establece como una variable de estado en
getInitialState
y se pasa desde un componente principal.
Esto en sí mismo funciona bien.
El problema surge cuando quiero actualizar el valor predeterminado de start_time a través del componente principal.
La actualización en sí ocurre en el componente principal a través de
setState start_time: new_time
.
Sin embargo, en mi formulario, el valor predeterminado start_time nunca cambia, ya que solo se define una vez en
getInitialState
.
Intenté usar
componentWillUpdate
para forzar un cambio de estado a través de
setState start_time: next_props.start_time
, que realmente funcionó, pero me dio
Uncaught RangeError: Maximum call stack size exceeded
errores.
Entonces mi pregunta es, ¿cuál es la forma correcta de actualizar el estado en este caso? ¿Estoy pensando en esto mal de alguna manera?
Código actual:
@ModalBody = React.createClass
getInitialState: ->
start_time: @props.start_time.format("HH:mm")
#works but takes long and causes:
#"Uncaught RangeError: Maximum call stack size exceeded"
componentWillUpdate: (next_props, next_state) ->
@setState(start_time: next_props.start_time.format("HH:mm"))
fieldChanged: (fieldName, event) ->
stateUpdate = {}
stateUpdate[fieldName] = event.target.value
@setState(stateUpdate)
render: ->
React.DOM.div
className: "modal-body"
React.DOM.form null,
React.createElement FormLabelInputField,
type: "time"
id: "start_time"
label_name: "Start Time"
value: @state.start_time
onChange: @fieldChanged.bind(null, "start_time”)
@FormLabelInputField = React.createClass
render: ->
React.DOM.div
className: "form-group"
React.DOM.label
htmlFor: @props.id
@props.label_name + ": "
React.DOM.input
className: "form-control"
type: @props.type
id: @props.id
value: @props.value
onChange: @props.onChange
Aparentemente las cosas están cambiando ... getDerivedStateFromProps() es ahora la función preferida.
class Component extends React.Component {
static getDerivedStateFromProps(props, current_state) {
if (current_state.value !== props.value) {
return {
value: props.value,
computed_prop: heavy_computation(props.value)
}
}
return null
}
}
Creo que usar ref es seguro para mí, no necesito preocuparme por algún método anterior.
class Company extends XComponent {
constructor(props) {
super(props);
this.data = {};
}
fetchData(data) {
this.resetState(data);
}
render() {
return (
<Input ref={c => this.data[''name''] = c} type="text" className="form-control" />
);
}
}
class XComponent extends Component {
resetState(obj) {
for (var property in obj) {
if (obj.hasOwnProperty(property) && typeof this.data[property] !== ''undefined'') {
if ( obj[property] !== this.data[property].state.value )
this.data[property].setState({value: obj[property]});
else continue;
}
continue;
}
}
}
De la documentación de reacción: https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
El estado de borrado cuando los accesorios cambian es un Anti Patrón
Desde React 16, componentWillReceiveProps está en desuso. De la documentación de reacción, el enfoque recomendado en este caso es el uso
-
Componente totalmente controlado: el
ParentComponent
deModalBody
será el propietario del estadostart_time
. Este no es mi enfoque preferido en este caso, ya que creo que el modal debería ser el propietario de este estado. -
Componente totalmente incontrolado con una clave: este es mi enfoque preferido.
Un ejemplo de la documentación de reacción:
https://codesandbox.io/s/6v1znlxyxn
.
Sería dueño del estado
start_time
de suModalBody
y usaríagetInitialState
tal como ya lo hizo. Para restablecer el estadostart_time
, simplemente cambie la clave delParentComponent
Es bastante claro de sus documentos:
If you used componentWillReceiveProps for re-computing some data only when a prop changes, use a memoization helper instead.
La nueva forma de hacerlo es usar useEffect en lugar de componentWillReceiveProps de la manera anterior:
componentWillReceiveProps(nextProps) {
// You don''t have to do this check first, but it can help prevent an unneeded render
if (nextProps.startTime !== this.state.startTime) {
this.setState({ startTime: nextProps.startTime });
}
}
se convierte en lo siguiente en un componente funcional impulsado por ganchos:
// store the startTime prop in local state
const [startTime, setStartTime] = useState(props.startTime)
//
useEffect(() => {
if (props.startTime !== startTime) {
setStartTime(props.startTime);
}
}, [props.startTime]);
configuramos el estado usando setState, usando useEffect, verificamos los cambios en el accesorio especificado y tomamos la acción para actualizar el estado al cambiar el accesorio.
Si lo entiendo correctamente, ¿tiene un componente principal que está pasando
start_time
al componente
ModalBody
que lo asigna a su propio estado?
Y desea actualizar ese tiempo desde el componente primario, no desde un componente secundario.
React tiene algunos consejos para lidiar con este escenario. (Tenga en cuenta que este es un artículo antiguo que desde entonces se ha eliminado de la web. Aquí hay un enlace al documento actual sobre accesorios de componentes ).
El uso de accesorios para generar estado en
getInitialState
menudo conduce a la duplicación de "fuente de verdad", es decir, dónde están los datos reales. Esto se debe a quegetInitialState
solo se invoca cuando el componente se crea por primera vez.Siempre que sea posible, calcule los valores sobre la marcha para asegurarse de que no se desincronicen más adelante y causen problemas de mantenimiento.
Básicamente, cada vez que asigna los
props
de los padres al
state
un niño, el método de representación no siempre se llama en la actualización de accesorios.
Debe invocarlo manualmente, utilizando el método
componentWillReceiveProps
.
componentWillReceiveProps(nextProps) {
// You don''t have to do this check first, but it can help prevent an unneeded render
if (nextProps.startTime !== this.state.startTime) {
this.setState({ startTime: nextProps.startTime });
}
}
También hay componentDidUpdate disponible.
Función firmante:
<EmailInput
defaultEmail={this.props.user.email}
key={this.props.user.id}
/>
Use esto como una oportunidad para operar en el DOM cuando el componente se haya actualizado.
No se llama en el
render
inicial.
Consulte
Probablemente no necesite el
artículo de
estado derivado
, que describe Anti-Pattern tanto para
componentDidUpdate
como para
getDerivedStateFromProps
.
Lo encontré muy útil.
Probablemente no necesite estado derivado
1. Establecer una clave del padre
Cuando una clave cambia, React creará una nueva instancia de componente en lugar de actualizar la actual. Las claves se usan generalmente para listas dinámicas, pero también son útiles aquí.
2. Utilice
getDerivedStateFromProps
/
componentWillReceiveProps
Si la clave no funciona por alguna razón (quizás el componente es muy costoso de inicializar)
Al usar
getDerivedStateFromProps
puede restablecer cualquier parte del estado, ¡pero parece un poco defectuoso en este momento (v16.7) !, vea
el enlace de arriba
para el uso
componentWillReceiveProps
está en desuso porque su uso "a menudo genera errores e inconsistencias".
Si algo cambia desde el exterior, considere restablecer el componente secundario por completo con la
key
.
Proporcionar una
key
apoyo al componente secundario asegura que siempre que el valor de la
key
cambie desde el exterior, este componente se vuelva a representar.
P.ej,
componentDidUpdate(prevProps, prevState, snapshot)
Sobre su rendimiento:
Si bien esto puede sonar lento, la diferencia de rendimiento suele ser insignificante. El uso de una clave puede incluso ser más rápido si los componentes tienen una lógica pesada que se ejecuta en las actualizaciones, ya que las diferencias se omiten para ese subárbol.