Apa cara yang benar untuk memperbarui status, apakah objek bersarang, di React with Hooks?
export Example = () => {
const [exampleState, setExampleState] = useState(
{masterField: {
fieldOne: "a",
fieldTwo: {
fieldTwoOne: "b"
fieldTwoTwo: "c"
}
}
})
Bagaimana cara yang digunakan setExampleState
untuk memperbarui exampleState
ke a
(menambahkan bidang)?
const a = {
masterField: {
fieldOne: "a",
fieldTwo: {
fieldTwoOne: "b",
fieldTwoTwo: "c"
}
},
masterField2: {
fieldOne: "c",
fieldTwo: {
fieldTwoOne: "d",
fieldTwoTwo: "e"
}
},
}
}
b
(Mengubah nilai)?
const b = {masterField: {
fieldOne: "e",
fieldTwo: {
fieldTwoOne: "f"
fieldTwoTwo: "g"
}
}
})
javascript
reactjs
react-hooks
isaacsultan
sumber
sumber
Jawaban:
Anda bisa memberikan nilai baru seperti ini
setExampleState({...exampleState, masterField2: { fieldOne: "c", fieldTwo: { fieldTwoOne: "d", fieldTwoTwo: "e" } }, }})
sumber
masterField
alih-alihmasterField2
setExampleState({...exampleState, masterField:
{// nilai baru}setExampleState( exampleState => ({...exampleState, masterField2: {...etc} }) );
Umumnya Anda harus berhati-hati terhadap objek bersarang dalam dalam status React. Untuk menghindari perilaku yang tidak terduga, status harus selalu diperbarui. Saat Anda memiliki objek dalam, Anda akhirnya akan melakukan kloning mendalam untuk mengetahui kekekalan, yang bisa sangat mahal di React. Mengapa?
Setelah Anda melakukan deep clone state, React akan menghitung ulang dan merender ulang semua yang bergantung pada variabel, meskipun variabel tersebut tidak berubah!
Jadi, sebelum mencoba menyelesaikan masalah Anda, pikirkan bagaimana Anda dapat meratakan keadaan terlebih dahulu. Segera setelah Anda melakukannya, Anda akan menemukan alat cantik yang akan membantu menangani status besar, seperti useReducer ().
Jika Anda memikirkannya, tetapi masih yakin bahwa Anda perlu menggunakan pohon status bersarang yang dalam, Anda masih bisa menggunakan useState () dengan pustaka seperti immutable.js dan Immutability-helper . Mereka membuatnya mudah untuk memperbarui atau mengkloning objek yang dalam tanpa harus khawatir tentang mutabilitas.
sumber
Jika ada yang mencari update hook useState () untuk objek
- 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' }));
sumber
Terima kasih Philip, ini membantu saya - kasus penggunaan saya adalah saya memiliki formulir dengan banyak bidang input jadi saya mempertahankan status awal sebagai objek dan saya tidak dapat memperbarui status objek. Posting di atas membantu saya :)
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} />
sumber
Saya terlambat ke pesta .. :)
Jawaban @aseferov bekerja dengan sangat baik ketika tujuannya adalah untuk memasukkan kembali seluruh struktur objek. Namun, jika target / sasaran adalah memperbarui nilai bidang tertentu di Objek, saya yakin pendekatan di bawah ini lebih baik.
situasi:
const [infoData, setInfoData] = useState({ major: { name: "John Doe", age: "24", sex: "M", }, minor:{ id: 4, collegeRegion: "south", } });
Memperbarui catatan tertentu akan membutuhkan penarikan kembali ke Status sebelumnya
prevState
Sini:
setInfoData((prevState) => ({ ...prevState, major: { ...prevState.major, name: "Tan Long", } }));
mungkin
setInfoData((prevState) => ({ ...prevState, major: { ...prevState.major, name: "Tan Long", }, minor: { ...prevState.minor, collegeRegion: "northEast" }));
Saya harap ini membantu siapa pun yang mencoba memecahkan masalah serupa.
sumber
()
:: Untuk menjawab ini secara sederhana; itu karenasetInfoData
sifatnya yang tinggi, yaitu dapat mengambil fungsi lain sebagai argumen, berkat kekuatan yang disediakan oleh Hook: useState. Saya harap artikel ini akan memberikan kejelasan lebih lanjut tentang fungsi tingkat tinggi: 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> ); }
sumber
Saya pikir solusi terbaik adalah Immer . Ini memungkinkan Anda untuk memperbarui objek seperti Anda mengubah bidang secara langsung (masterField.fieldOne.fieldx = 'abc'). Tapi itu tidak akan mengubah objek yang sebenarnya tentunya. Ini mengumpulkan semua pembaruan pada objek draf dan memberi Anda objek akhir di bagian akhir yang dapat Anda gunakan untuk menggantikan objek asli.
sumber
Saya meninggalkan Anda fungsi utilitas untuk memperbarui objek secara pasti
/** * 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 }; };
Jadi Anda bisa menggunakannya seperti ini
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 }
Jika tidak, Anda memiliki lebih banyak utilitas di sini: https://es.reactjs.org/docs/update.html
sumber
Awalnya saya menggunakan objek di useState, tetapi kemudian saya pindah ke hook useReducer untuk kasus yang kompleks. Saya merasakan peningkatan kinerja ketika saya mengubah kode.
useReducer React docs
Saya sudah menerapkan pengait seperti itu untuk penggunaan saya sendiri:
/** * 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); } }, ]; }
lebih banyak kait terkait .
sumber