¿Cuál es la forma correcta de actualizar el estado, es un objeto anidado, en React with Hooks?
export Example = () => {
const [exampleState, setExampleState] = useState(
{masterField: {
fieldOne: "a",
fieldTwo: {
fieldTwoOne: "b"
fieldTwoTwo: "c"
}
}
})
¿Cómo se usaría setExampleState
para actualizar exampleState
a a
(agregar un campo)?
const a = {
masterField: {
fieldOne: "a",
fieldTwo: {
fieldTwoOne: "b",
fieldTwoTwo: "c"
}
},
masterField2: {
fieldOne: "c",
fieldTwo: {
fieldTwoOne: "d",
fieldTwoTwo: "e"
}
},
}
}
b
(Cambio de valores)?
const b = {masterField: {
fieldOne: "e",
fieldTwo: {
fieldTwoOne: "f"
fieldTwoTwo: "g"
}
}
})
javascript
reactjs
react-hooks
isaacsultan
fuente
fuente
Respuestas:
Puedes pasar un nuevo valor como este
setExampleState({...exampleState, masterField2: { fieldOne: "c", fieldTwo: { fieldTwoOne: "d", fieldTwoTwo: "e" } }, }})
fuente
masterField
lugar demasterField2
setExampleState({...exampleState, masterField:
{// nuevos valores}setExampleState( exampleState => ({...exampleState, masterField2: {...etc} }) );
En general, debe tener cuidado con los objetos profundamente anidados en el estado React. Para evitar un comportamiento inesperado, el estado debe actualizarse de forma inmutable. Cuando tienes objetos profundos, terminas clonándolos en profundidad por inmutabilidad, lo que puede ser bastante costoso en React. ¿Por qué?
Una vez que clone en profundidad el estado, React recalculará y volverá a renderizar todo lo que depende de las variables, ¡aunque no hayan cambiado!
Por lo tanto, antes de intentar resolver su problema, piense cómo puede aplanar el estado primero. Tan pronto como lo haga, encontrará hermosas herramientas que lo ayudarán a lidiar con estados grandes, como useReducer ().
En caso de que lo haya pensado, pero aún está convencido de que necesita usar un árbol de estado profundamente anidado, aún puede usar useState () con bibliotecas como immutable.js e Immutability-helper . Hacen que sea sencillo actualizar o clonar objetos profundos sin tener que preocuparse por la mutabilidad.
fuente
Si alguien está buscando useState (), actualice los ganchos para el objeto
- Through Input const [state, setState] = useState({ fName: "", lName: "" }); const handleChange = e => { const { name, value } = e.target; setState(prevState => ({ ...prevState, [name]: value })); }; <input value={state.fName} type="text" onChange={handleChange} name="fName" /> <input value={state.lName} type="text" onChange={handleChange} name="lName" /> *************************** - Through onSubmit or button click setState(prevState => ({ ...prevState, fName: 'your updated value here' }));
fuente
Gracias, Felipe, esto me ayudó: mi caso de uso fue que tenía un formulario con muchos campos de entrada, así que mantuve el estado inicial como objeto y no pude actualizar el estado del objeto. La publicación anterior me ayudó :)
const [projectGroupDetails, setProjectGroupDetails] = useState({ "projectGroupId": "", "projectGroup": "DDD", "project-id": "", "appd-ui": "", "appd-node": "" }); const inputGroupChangeHandler = (event) => { setProjectGroupDetails((prevState) => ({ ...prevState, [event.target.id]: event.target.value })); } <Input id="projectGroupId" labelText="Project Group Id" value={projectGroupDetails.projectGroupId} onChange={inputGroupChangeHandler} />
fuente
Llego tarde a la fiesta .. :)
La respuesta de @aseferov funciona muy bien cuando la intención es volver a ingresar a toda la estructura del objeto. Sin embargo, si el objetivo / objetivo es actualizar un valor de campo específico en un Objeto, creo que el enfoque a continuación es mejor.
situación:
const [infoData, setInfoData] = useState({ major: { name: "John Doe", age: "24", sex: "M", }, minor:{ id: 4, collegeRegion: "south", } });
La actualización de un registro específico requerirá hacer un retiro del estado anterior
prevState
Aquí:
setInfoData((prevState) => ({ ...prevState, major: { ...prevState.major, name: "Tan Long", } }));
quizás
setInfoData((prevState) => ({ ...prevState, major: { ...prevState.major, name: "Tan Long", }, minor: { ...prevState.minor, collegeRegion: "northEast" }));
Espero que esto ayude a cualquiera que intente resolver un problema similar.
fuente
()
:: Para responder esto simplemente; es porquesetInfoData
es de alto orden por naturaleza, es decir, puede tomar otra función como argumento, cortesía del poder proporcionado por el Hook: useState. Espero que este artículo brinde más claridad sobre las funciones de orden superior: sitepoint.com/higher-order-functions-javascriptfunction App() { const [todos, setTodos] = useState([ { id: 1, title: "Selectus aut autem", completed: false }, { id: 2, title: "Luis ut nam facilis et officia qui", completed: false }, { id: 3, title: "Fugiat veniam minus", completed: false }, { id: 4, title: "Aet porro tempora", completed: true }, { id: 5, title: "Laboriosam mollitia et enim quasi", completed: false } ]); const changeInput = (e) => {todos.map(items => items.id === parseInt(e.target.value) && (items.completed = e.target.checked)); setTodos([...todos], todos);} return ( <div className="container"> {todos.map(items => { return ( <div key={items.id}> <label> <input type="checkbox" onChange={changeInput} value={items.id} checked={items.completed} /> {items.title}</label> </div> ) })} </div> ); }
fuente
Creo que la mejor solución es Immer . Le permite actualizar el objeto como si estuviera modificando campos directamente (masterField.fieldOne.fieldx = 'abc'). Pero, por supuesto, no cambiará el objeto real. Recopila todas las actualizaciones de un objeto de borrador y le brinda un objeto final al final que puede usar para reemplazar el objeto original.
fuente
Te dejo una función de utilidad para actualizar objetos de forma inmutable
/** * Inmutable update object * @param {Object} oldObject Object to update * @param {Object} updatedValues Object with new values * @return {Object} New Object with updated values */ export const updateObject = (oldObject, updatedValues) => { return { ...oldObject, ...updatedValues }; };
Entonces puedes usarlo así
const MyComponent = props => { const [orderForm, setOrderForm] = useState({ specialities: { elementType: "select", elementConfig: { options: [], label: "Specialities" }, touched: false } }); // I want to update the options list, to fill a select element // ---------- Update with fetched elements ---------- // const updateSpecialitiesData = data => { // Inmutably update elementConfig object. i.e label field is not modified const updatedOptions = updateObject( orderForm[formElementKey]["elementConfig"], { options: data } ); // Inmutably update the relevant element. const updatedFormElement = updateObject(orderForm[formElementKey], { touched: true, elementConfig: updatedOptions }); // Inmutably update the relevant element in the state. const orderFormUpdated = updateObject(orderForm, { [formElementKey]: updatedFormElement }); setOrderForm(orderFormUpdated); }; useEffect(() => { // some code to fetch data updateSpecialitiesData.current("specialities",fetchedData); }, [updateSpecialitiesData]); // More component code }
Si no tiene más utilidades aquí: https://es.reactjs.org/docs/update.html
fuente
Inicialmente usé object en useState, pero luego pasé a useReducer hook para casos complejos. Sentí una mejora en el rendimiento cuando refactoricé el código.
useReducer React docs
Ya implementé tal gancho para mi propio uso:
/** * Same as useObjectState but uses useReducer instead of useState * (better performance for complex cases) * @param {*} PropsWithDefaultValues object with all needed props * and their initial value * @returns [state, setProp] state - the state object, setProp - dispatch * changes one (given prop name & prop value) or multiple props (given an * object { prop: value, ...}) in object state */ export function useObjectReducer(PropsWithDefaultValues) { const [state, dispatch] = useReducer(reducer, PropsWithDefaultValues); //newFieldsVal={[field_name]: [field_value], ...} function reducer(state, newFieldsVal) { return { ...state, ...newFieldsVal }; } return [ state, (newFieldsVal, newVal) => { if (typeof newVal !== "undefined") { const tmp = {}; tmp[newFieldsVal] = newVal; dispatch(tmp); } else { dispatch(newFieldsVal); } }, ]; }
ganchos más relacionados .
fuente