Soy nuevo en React.js y estoy creando un componente de selección personalizado donde se supone que debe establecer un estado seleccionado de matriz y también desencadenar un evento de cambio y pasarlo al padre con los elementos seleccionados y también obtener el valor inicial como accesorio y establecer algunos datos.
let firstTime = true;
const CustomSelect = (props)=>{
const [selected, setSelected] = useState([]);
const onSelectedHandler = (event)=>{
// remove if already included in the selected items remove
//otherwise add
setSelected((prev)=>{
if (selected.includes(value)) {
values = prevState.filter(item => item !== event.target.value);
}else {
values = [...prevState, event.target.value];
}
return values;
})
// tried calling props.onSelection(selected) but its not latest value
}
//watch when the value of selected is updated and pass onchange to parent
//with the newest value
useEffect(()=>{
if(!firstTime && props.onSelection){
props.onSelection(selected);
}
firstTime = false;
},[selected])
return (<select onChange={onSelectedHandler}>
<option value="1"></option>
</select>);
};
Lo estoy usando en un padre como
const ParentComponent = ()=>{
const onSelectionHandler = (val)=>{
//do stuff with the value passed
}
return (
<CustomSelect initialValue={[1,2]} onSelection={onSelectionHandler} />
);
}
export default ParentComponent
Lo anterior funciona bien, pero ahora surge el problema cuando quiero establecer el valor inicial pasado del padre a customSelect actualizando el estado seleccionado. He agregado lo siguiente en CustomSelect, pero provoca un bucle infinito
const {initialValue} = props
useEffect(()=>{
//check if the value of initialValue is an array
//and other checks
setSelected(initialValue)
},[initialValue]);
Entiendo que podría haber pasado el valor inicial en el estado de uso, pero me gustaría hacer un par de comprobaciones antes de establecer el estado seleccionado. ¿Cómo puedo resolver esto? Todavía soy nuevo en React.js.
En su //do stuff with the value passed , lo más probable es que actualice los estados del componente principal de su componente y provoque que se vuelva a procesar el componente principal. Al pasar el prop initialValue={[1,2]} crea una nueva instancia de matriz [1,2] en cada procesamiento y provoca el procesamiento infinito en useEffect. Para resolver esto, puede mover la propiedad initialValue a otro lugar como valor constante como este:
const INITIAL_VALUE_PROP = [1,2];
const ParentComponent = ()=>{
const onSelectionHandler = (val)=>{
//do stuff with the value passed
}
return (
<CustomSelect initialValue={INITIAL_VALUE_PROP} onSelection={onSelectionHandler}
/>
);
}
export default ParentComponent
De acuerdo, la razón por la que esto sucede es que está pasando la propiedad initialValue como una matriz, y dado que este es un valor de referencia en JavaScript, significa que cada vez que se pasa (actualiza), se pasa con un valor de referencia diferente/ dirección, por lo que el efecto seguirá ejecutándose infinitamente. Una forma de resolver esto es usar React.useMemo , documentación aquí para almacenar/preservar el valor de referencia de la matriz pasada, para no causar efectos secundarios innecesarios.