리액트 후크 useState()와 오브젝트
중첩된 개체에서 후크로 반응에서 상태를 업데이트하는 올바른 방법은 무엇입니까?
export Example = () => {
const [exampleState, setExampleState] = useState(
{masterField: {
fieldOne: "a",
fieldTwo: {
fieldTwoOne: "b"
fieldTwoTwo: "c"
}
}
})
사용합니까?setExampleState
exampleState
로로 합니다.a
( 드 ( (추 )
const a = {
masterField: {
fieldOne: "a",
fieldTwo: {
fieldTwoOne: "b",
fieldTwoTwo: "c"
}
},
masterField2: {
fieldOne: "c",
fieldTwo: {
fieldTwoOne: "d",
fieldTwoTwo: "e"
}
},
}
}
b
( 의 ( (변 )
const b = {masterField: {
fieldOne: "e",
fieldTwo: {
fieldTwoOne: "f"
fieldTwoTwo: "g"
}
}
})
다음과 같이 새 값을 전달할 수 있습니다.
setExampleState({...exampleState, masterField2: {
fieldOne: "a",
fieldTwo: {
fieldTwoOne: "b",
fieldTwoTwo: "c"
}
},
})
useState() hooks update for object를 검색하는 사용자가 있는 경우
- 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'
}));
일반적으로 리액트 상태의 깊이 중첩된 객체에 주의해야 합니다.예기치 않은 동작을 방지하려면 상태를 항상 업데이트해야 합니다.깊은 객체가 있으면 불변성을 위해 깊은 복제를 하게 되는데, 리액트에서는 상당히 비용이 많이 들 수 있습니다. 왜일까요?
상태를 자세히 복제하면 변수에 따라 달라지지 않은 모든 변수가 다시 계산되고 다시 렌더링됩니다.
그러니 문제를 해결하려고 하기 전에 어떻게 하면 국가를 평탄하게 만들 수 있을지 생각해 보세요.즉시 useReducer()와 같은 대규모 상태에 대처하는 데 도움이 되는 편리한 도구를 찾을 수 있습니다.
깊이 중첩된 상태 트리를 사용할 필요가 있다고 확신하는 경우에도 useState()를 unimputable.js 및 Imputability-helper와 같은 라이브러리와 함께 사용할 수 있습니다.이러한 기능을 통해 깊은 개체를 쉽게 업데이트하거나 복제할 수 있으며, 변동성을 걱정할 필요가 없습니다.
파티에 늦어서..:)
@aseferov의 답변은 오브젝트 구조 전체에 재진입하는 경우에 매우 효과적입니다.단, 오브젝트 내의 특정 필드 값을 갱신하는 것이 목표/목표라면 아래 방법이 더 좋다고 생각합니다.
상황:
const [infoData, setInfoData] = useState({
major: {
name: "John Doe",
age: "24",
sex: "M",
},
minor:{
id: 4,
collegeRegion: "south",
}
});
하려면 이전 .prevState
여기:
setInfoData((prevState) => ({
...prevState,
major: {
...prevState.major,
name: "Tan Long",
}
}));
아마
setInfoData((prevState) => ({
...prevState,
major: {
...prevState.major,
name: "Tan Long",
},
minor: {
...prevState.minor,
collegeRegion: "northEast"
}));
나는 이것이 비슷한 문제를 해결하려는 사람들에게 도움이 되기를 바란다.
할 수 useReducer
스테이트를 하기 위한 으로, 「」이 아닌 「 스테이트를 관리할 수 .useState
그러기 위해서는 먼저 다음과 같이 상태 및 업데이트 기능을 초기화합니다.
const initialState = { name: "Bob", occupation: "builder" };
const [state, updateState] = useReducer(
(state, updates) => ({ ...state, ...updates }),
initialState
);
그런 다음 다음과 같이 부분 업데이트만 전달하여 상태를 업데이트할 수 있습니다.
updateState({ occupation: "postman" })
Philip 덕분에 많은 입력 필드가 있는 폼이 있었기 때문에 오브젝트로서의 초기 상태를 유지하고 오브젝트 상태를 갱신할 수 없었습니다.위의 투고가 도움이 되었습니다:)
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}
/>
2022년
「 」와 같은 .this.setState
.class components
의 in ) ) 。functional components
그러면 이게 당신에게 많은 도움이 되는 대답이에요.
예를들면
과 같은 때, '하다'를 .object destructing
매번 그리고 때로는 짜증날 것이다.
const [state, setState] = useState({first: 1, second: 2});
// results will be state = {first: 3} instead of {first: 3, second: 2}
setState({first: 3})
// To resolve that you need to use object destructing every time
// results will be state = {first: 3, second: 2}
setState(prev => ({...prev, first: 3}))
는 그그 the the 를 생각해 냈다.useReducer
접근.useReducer를 확인하십시오.
const stateReducer = (state, action) => ({
...state,
...(typeof action === 'function' ? action(state) : action),
});
const [state, setState] = useReducer(stateReducer, {first: 1, second: 2});
// results will be state = {first: 3, second: 2}
setState({first: 3})
// you can also access the previous state callback if you want
// results will remain same, state = {first: 3, second: 2}
setState(prev => ({...prev, first: 3}))
장장은 할 수 .stateReducer
utils
수입하다
.custom hook
네가 원한다면.
import React from 'react';
export const stateReducer = (state, action) => ({
...state,
...(typeof action === 'function' ? action(state) : action),
});
const useReducer = (initial, lazyInitializer = null) => {
const [state, setState] = React.useReducer(stateReducer, initial, init =>
lazyInitializer ? lazyInitializer(init) : init
);
return [state, setState];
};
export default useReducer;
타이프 스크립트
import React, { Dispatch } from "react";
type SetStateAction<S> = S | ((prev: S) => S);
type STATE<R> = [R, Dispatch<SetStateAction<Partial<R>>>];
const stateReducer = (state, action) => ({
...state,
...(typeof action === "function" ? action(state) : action),
});
const useReducer = <S>(initial, lazyInitializer = null): STATE<S> => {
const [state, setState] = React.useReducer(stateReducer, initial, (init) =>
lazyInitializer ? lazyInitializer(init) : init,
);
return [state, setState];
};
export default useReducer;
Rest 파라미터와 spread 구문을 사용해야 합니다(https://javascript.info/rest-parameters-spread) 그리고 setState 인수로서 preState를 사용하여 함수를 설정해야 합니다.
작동하지 않음(함수 누락)
[state, setState] = useState({})
const key = 'foo';
const value = 'bar';
setState({
...state,
[key]: value
});
효과가 있다!
[state, setState] = useState({})
const key = 'foo';
const value = 'bar';
setState(prevState => ({
...prevState,
[key]: value
}));
Adpend, Whole object update, 문제 해결을 위한 특정 키 업데이트 예를 모두 제시했습니다.
추가 및 수정은 간단한 절차로 수행할 수 있습니다.나는 이것이 불변하거나 변하기 쉬운 의존관계가 없는 더 안정적이고 안전하다고 생각한다.
이렇게 하면 새 개체를 추가할 수 있습니다.
setExampleState(prevState => ({
...prevState,
masterField2: {
fieldOne: "c",
fieldTwo: {
fieldTwoOne: "d",
fieldTwoTwo: "e"
}
},
}))
masterField2 개체를 다시 변경하는 경우를 가정합니다.두 가지 상황이 있을 수 있습니다.개체 전체를 업데이트하거나 개체의 특정 키를 업데이트하려고 합니다.
개체 전체 업데이트 - 여기서 masterField2 키의 전체 값이 업데이트됩니다.
setExampleState(prevState => ({
...prevState,
masterField2: {
fieldOne: "c",
fieldTwo: {
fieldTwoOne: "d",
fieldTwoTwo: "e"
}
},
}))
단, masterField2 오브젝트 내의 fieldTwoOne 키만 변경하는 경우에는 어떻게 해야 합니까?다음을 수행합니다.
let oldMasterField2 = exampleState.masterField2
oldMasterField2.fieldTwo.fieldTwoOne = 'changed';
setExampleState(prevState => ({
...prevState,
masterField2: oldMasterField2
}))
function 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>
);
}
처음에는 useState에서 객체를 사용했지만, 복잡한 경우 useReducer 훅으로 이동했습니다.코드를 리팩터링 했을 때 성능 향상을 느꼈습니다.
useReducer는 일반적으로 여러 서브값을 포함하는 복잡한 상태 로직이 있는 경우 또는 다음 상태가 이전 상태에 의존하는 경우 useState보다 선호됩니다.
이 훅은 이미 제 용도로 실장되어 있습니다.
/**
* 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);
}
},
];
}
관련성이 높은 후크
, 다음의 예와 같이 실행합니다.
먼저 오브젝트 상태를 만듭니다.
const [isSelected, setSelection] = useState([{ id_1: false }, { id_2: false }, { id_3: false }]);
그 값을 변경합니다.
// if the id_1 is false make it true or return it false.
onValueChange={() => isSelected.id_1 == false ? setSelection([{ ...isSelected, id_1: true }]) : setSelection([{ ...isSelected, id_1: false }])}
나는 이머가 가장 좋은 해결책이라고 생각한다.필드를 직접 수정하는 것처럼 개체를 업데이트할 수 있습니다(masterField.fieldOne.fieldx = 'field').하지만 물론 그것은 실제 목적을 바꾸지는 않을 것이다.임시 객체에 대한 모든 업데이트를 수집하고 마지막에 원래 객체를 대체하는 데 사용할 수 있는 최종 객체를 제공합니다.
부울값 및 어레이를 사용하는 경우 다음과 같은 이점이 있습니다.
const [checkedOrders, setCheckedOrders] = useState<Record<string, TEntity>>({});
const handleToggleCheck = (entity: TEntity) => {
const _checkedOrders = { ...checkedOrders };
const isChecked = entity.id in checkedOrders;
if (isChecked) {
delete _checkedOrders[entity.id];
} else {
_checkedOrders[entity.id] = entity;
}
setCheckedOrders(_checkedOrders);
};
오브젝트를 상호 갱신할 수 있는 유틸리티 기능을 남깁니다.
/**
* 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
};
};
그래서 이렇게 쓸 수 있어요.
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
}
기타 유틸리티가 없는 경우 https://es.reactjs.org/docs/update.html 를 참조하십시오.
스테이트로 하는 오브젝트
let teams = {
team: [
{
name: "one",
id: "1"
},
]
}
팀의 상태를 오브젝트화하다
const [state, setState] = useState(teams);
다음과 같이 상태 업데이트
setState((prevState)=>({...prevState,team:[
...prevState.team,
{
name: "two",
id: "2"
}
]}))
업데이트 상태가 된 후
{
team: [
{
name: "one",
id: "1"
},
{
name: "two",
id: "2"
}
]
}
현재 상태에 따라 항목을 렌더링하려면 지도 기능을 사용합니다.
{state.team.map((curr_team) => {
return (
<div>
<p>{curr_team.id}</p>
<p>{curr_team.name}</p>
</div>
)
})}
보다 우아한 해결책은 이전의 상태 값을 유지하면서 업데이트된 상태 개체를 만드는 것이라고 생각합니다.갱신해야 할 오브젝트 속성은 다음과 같은 배열 형태로 제공될 수 있습니다.
import React,{useState, useEffect} from 'react'
export default function Home2(props) {
const [x, setX] = useState({name : '',add : {full : '', pin : '', d : { v : '' }}})
const handleClick = (e, type)=>{
let obj = {}
if(type.length > 1){
var z = {}
var z2 = x[type[0]]
type.forEach((val, idx)=>{
if(idx === type.length - 1){
z[val] = e.target.value
}
else if(idx > 0){
Object.assign(z , z2) /*{...z2 , [val]:{} }*/
z[val] = {}
z = z[val]
z2 = z2[val]
}else{
z = {...z2}
obj = z
}
})
}else obj = e.target.value
setX( { ...x , [type[0]] : obj } )
}
return (
<div>
<input value = {x.name} onChange={e=>handleClick(e,["name"])}/>
<input value = {x.add.full} onChange={e=>handleClick(e,["add","full"])} />
<input value = {x.add.pin} onChange={e=>handleClick(e,["add","pin"])} /><br/>
<input value = {x.add.d.v} onChange={e=>handleClick(e,["add","d","v"])} /><br/>
{x.name} <br/>
{x.add.full} <br/>
{x.add.pin} <br/>
{x.add.d.v}
</div>
)
}
언급URL : https://stackoverflow.com/questions/54150783/react-hooks-usestate-with-object
'programing' 카테고리의 다른 글
Java에서의 합성 클래스 (0) | 2022.11.08 |
---|---|
x**.5와 math.sqrt(x) 중 어느 쪽이 Python에서 더 빠릅니까? (0) | 2022.11.07 |
mariadb 이미지에 대해 루트 사용자가 아닌 도커 컨테이너를 실행할 수 없습니다. (0) | 2022.11.07 |
Chrome에서 탭이 비활성 상태일 때 setInterval도 작동하도록 하려면 어떻게 해야 합니까? (0) | 2022.11.07 |
브라우저 뷰포트에 상대적인 요소의 맨 위 위치를 가져오려면 어떻게 해야 합니까? (0) | 2022.11.07 |