ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React] state 변경 함수의 동작 원리? ( + 스프레드 연산자 )
    React 2023. 10. 23. 17:54

      let [clickedCells, setClickedCells] = useState([]); // 클릭된 셀의 위치를 배열로 저장
    
      var row = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
    
      const handleCellClick = (i, j) => {
        setClickedCells([...clickedCells, {i,j}]); // 클릭된 셀의 위치를 배열에 추가 
      }

     오목 게임 프로젝트 때 작성했던 코드이다. state를 만들어 클릭된 셀의 위치를 저장하는데 셀을 클릭할 때마다 클릭된 셀의 위치를 배열에 추가하는 함수를 만들어본 것인데, 이와 같이 array, object state 변경하는 법 및 동작원리에 대해 자세히 알아보고 싶어졌다.


    아래 코드는 버튼을 클릭하면 첫번째 배열 요소 이름이 바뀌는 코드이다.  

    function App() {
      let [name, setName] = useState(['kim', 'Hee', 'Lee']);
    
      return (
          <button onClick={ () => {
            let copy = [...name];
            copy[0] = 'Min';
            setName(name)
          }}>이름변경</button>
      );
    }

    array나 object 자료를 다룰 때는 원본요소인 name을 직접 수정하는 것보다는 위의 코드처럼 copy같은 변수에 기존 array를 복사해놓은 후 코드를 짜는 것이 안전하다. 위의 state 변경함수 동작 원리를 알아보고자 한다. 

     

    [  state 변경 함수 동작 원리 ]

     state 변경 함수는 처음 동작시 기존 state와 신규 state가 같은지 (===) 검사한다. 만약 같다면 state 변경 해주지 않는데 아래 코드에서 보다시피 copy라는 변수가 기존 state인 name과 같기 때문에 setName(name) 함수가 동작하지 않는다고 한다. 음.. copy[0]에는 'Min'이 들어있고 name[0]에는 'kim'이 들어있는데 어떻게 같다고 나오는지..? 의문이 들었다. 

    function App() {
      let [name, setName] = useState(['kim', 'Hee', 'Lee']);
    
      return (
          <button onClick={ () => {
            let copy = name;
            copy[0] = 'Min';
            setName(name)
          }}>이름변경</button>
      );
    }

    이건 array 와 object의 동작원리를 통해 알 수 있다. 예를 들어 아래 코드에서 [1,2,3]은 램이라는 가상 공간에 저장되고 변수 arr1에는 [1,2,3]이 어디있는지 가리키는 화살표만 남아있다.  따라서 arr1자료를 arr2에 복사했을 때도 화살표가 복사되기 때문에 arr1과 arr2는 같은 값을 가리키므로 arr1의 값이 변경되면 arr2도 자동으로 변경된다. (자세한 내용은  javascript reference data type에서 공부하기)

      let arr1 = [1,2,3];
      let arr2 = arr1; // arr1자료 arr2에 복사
      arr1[0] = 1111;
      console.log(arr1 === arr2); // true

    그래서 copy라는 변수에 name이라는 변수의 화살표가 복사된 것이기 때문에 두 변수는 같은 값을 가리키고 있어 state 변경이 되지 않는다. 

    let copy = name;
    copy[0] = 'Min';
    setName(name)

    아래와 같이 [...name] 으로 써주면 잘 동작되는데 이는 스프레드 연산자( spread operator)라는 문법이다.  object 자료형에도 적용가능하며 괄호([ ]) 벗기기용 연산자라고 보면 된다.

    let copy = [...name];
    copy[0] = 'Min';
    setName(name)

    아래와 같이 [...arr1]을 하게 되면 arr1의 괄호를 벗긴 다음 다시 배열로 만들어달라는 뜻이기 때문에 새로운 배열로 인식을 해 화살표가 달라지게 된다. 그래서 보통 array나 object 자료형을 복사할 때 많이 사용한다. 

      let arr1 = [1,2,3];
      let arr2 = [...arr1];
      arr1[0] = 1111;
      console.log(arr1 === arr2); // false

    결론적으로 아래 코드에서도 [...name] 은 copy와 화살표가 다른 독립적인 array 복사본이 생성된 것이므로 state는 두 변수를 다르게 인식해 아래 setName(name) 이라는 state 변경함수가 잘 동작하게 된다. 이런 독립적 복사본을  shallow copy 아니면 deep copy 라고 하는데 나중에 자세히 알아봐야겠다. 

    function App() {
      let [name, setName] = useState(['kim', 'Hee', 'Lee']);
    
      return (
          <button onClick={ () => {
            let copy = [...name];
            copy[0] = 'Min';
            setName(name)
          }}>이름변경</button>
      );
    }

    'React' 카테고리의 다른 글

    [React] 컴포넌트 생명주기와 useEffect, clean up function  (0) 2023.10.27
Designed by Tistory.