programing

리액트 후크 useState()와 오브젝트

bestcode 2022. 11. 7. 22:09
반응형

리액트 후크 useState()와 오브젝트

중첩된 개체에서 후크로 반응에서 상태를 업데이트하는 올바른 방법은 무엇입니까?

export Example = () => {
  const [exampleState, setExampleState] = useState(
  {masterField: {
        fieldOne: "a",
        fieldTwo: {
           fieldTwoOne: "b"
           fieldTwoTwo: "c"
           }
        }
   })

사용합니까?setExampleStateexampleState로로 합니다.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.jsImputability-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}))

장장은 할 수 .stateReducerutils수입하다

.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} />&nbsp; {items.title}</label>
          </div>
        )
      })}
    </div>
  );
}

처음에는 useState에서 객체를 사용했지만, 복잡한 경우 useReducer 훅으로 이동했습니다.코드를 리팩터링 했을 때 성능 향상을 느꼈습니다.

useReducer는 일반적으로 여러 서브값을 포함하는 복잡한 상태 로직이 있는 경우 또는 다음 상태가 이전 상태에 의존하는 경우 useState보다 선호됩니다.

useReducer React 문서

이 훅은 이미 제 용도로 실장되어 있습니다.

/**
 * 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

반응형