안루피취뽀일기

조건적 콘텐츠 & State(상태) 업데이트 !매우간단하지만 중요한! 본문

React

조건적 콘텐츠 & State(상태) 업데이트 !매우간단하지만 중요한!

안루피 2024. 2. 1. 20:56
728x90

 


Edit이라고 된 수정버튼을 누르면 <input>창이 뜨고

수정버튼에는 Save으로 바뀌어 저장버튼이 되어 그걸 또 누르면

다시 수정버튼이 되는

매우 간단하지만 저엉말 많이 쓰이는 그런 버튼을 구현하는데

머리로는 매우 간단할 것 같다는 생각이 들지요!

과연 간단할까하는 합리적 의심

 

 

그렇다! 코드도 매우 간단하다!!!

하지만 알면 쉬운데 모르면 어려울 수 있는 고런거

아는게 힘!

 

import { useState } from "react";

export default function Player({ name, symbol }) {
  const [isEditing, setIsEditing] = useState(false);

  function handleEditClick() {
    setIsEditing(isEditing ? false : true);
  }

  //   let btnCaption = "Edit";

  let playerName = <span className="player-name">{name}</span>;

  if (isEditing) {
    playerName = <input type="text" required value={name} />;
    // btnCaption = "Save";
  }

  return (
    <li>
      <span className="player">
        {playerName}
        <span className="player-symbol">{symbol}</span>
      </span>
      <button onClick={handleEditClick}>{isEditing ? "Save" : "Edit"}</button>
    </li>
  );
}

 

 

setIsEditing(isEditing ? false : true);

 

=> isEditing이 지금 true이면 false로, false이면 true로 바꾸라는 간단한 삼항연산자.

 

 

 

허허 너무 쉽다 ㅎㅎ

하지만 ..!

 

더 간단한 방법이 있다는 거..

 

setIsEditing(!isEditing);

앞에 느낌표만 붙여주면 반전되지용~~~~~~~

 

 

그러나..

또 반전

이게 끝이 아니다

 

이러한 방식은 리액트에서 추천하지 않는다...!

새 State가 이전 State값에 따라 달라지는 경우 이와 같이 State를 업데이트해서는 안된다.

 

 

State를 이전 값에 기반하여 변경할 경우 함수를 하나 전달해야 하는데

해당 상태 변경 함수로 보내야 한다

 

왜 함수를 보내야 할까?

 

setIsEditing(( editing ) => !editing);

여기서 전달하는 이 함수를 리액트가 호출해서 자동적으로 현재 State값을 가지게 되게 때문이다.

즉 State 변경 전의 값이 입력된다.

 

매개변수를 하나 받는데, 이름은 editing으로 해주겠다.

이것또한 true 혹은 false인데, isEditing과 동일하다

 

하지만 editing 매개변수는 값으로 인식되어 

리액트가 함수 호출 시 동적으로 설정 및 전달하게 된다!

 

이 함수를 setIsEditing으로 전달할 때 설정하고자 하는 새로운 State를 반환하게 된다.

 

 

setIsEditing(!isEditing);

그리고 아까 코드의 문제점 2

작업을 수행하는 리액트가 상태에 대한 변화의 스케줄을 조율한다는 점이다.

setIsEditing 같은 상태 변경 함수를 통해 실행하고 있으니 단계로 이루어진다

상태 변경은 즉각적으로 수행되는 것이 아니라 리액트가 미래에 수행하고자 상태 변경 스케줄을 조율하는 것이다

 

 

만약 

 

 function handleEditClick() {
    setIsEditing(!isEditing);
    setIsEditing(!isEditing);
  }

 

이 코드가 실행된다면

setIsEditing을 true 설정한  다시 false 설정하기 때문에

아무 일도 일어나지 않을거라고 생각한다

 

그러나 대반전

 

예상한 결과와는 다르다

수정 버튼을 누르면 입력 창이 정상적으로 뜨고 저장을 누르면 사라진다

 

결과는

 function handleEditClick() {
    setIsEditing(!isEditing);
  }

 

번째 줄을 결과와 동일하다!!!!

 

 

이것이 함수 형태를 사용해야 하는 이유

리액트가 상태 변경 스케줄을 조율하는데 변화 모두 isEditing 현재 상태를 기준으로 실행된다

 

function handleEditClick() {
    setIsEditing(!isEditing);
    setIsEditing(!isEditing);
  }

 

시작점은 false

그래서 setIsEditing(!isEditing); setIsEditing(!isEditing); 이 두줄 모두

isEditing false 시점을 기준으로 한

컴포넌트 함수가 처음 실행되는 시점에 isEditing 값이 false이기 때문이다

 

setIsEditing isEditing 반대격으로 호출할 상태 변경 스케줄을 조율하게 되는데

이때 setIsEditing true 바꾸라는 명령이 즉각적으로 실행되지 않는다

다음 줄에서도 이전과 동일한 상태가 유지된다는 의미.

 

그 이유는 아직 동일한 컴포넌트 함수 실행의 사이클을 돌고 있기 때문이다

 

그리고 이 두 state 변화의 일정은 각자의 작업 이후에 실행된다

 

만약

 

function handleEditClick() {

    setIsEditing((editing) => !editing);

    setIsEditing((editing) => !editing);

  }

 

이렇게 함수형으로 만든다면 이제야 내가 예상한 아무것도 일어나지 않는 상태가 되는 것이다!

 

함수 형태를 사용한다면 리액트가 보장해줄 수 있는 것은 이 state값은 언제나 가장 최신 버전이라는 점!

기억하자구!!!!!!!!!!

 

728x90