👨‍💻 FrontEnd/React

[ React ] State - React의 State란?

hoonding 2023. 8. 2. 13:06

아래 글은 React 공식문서를 기반으로 작성된 글입니다.

 

State를 사용해 Input 다루기 – React

The library for web and native user interfaces

ko.react.dev


State로 입력에 반응하기

React는 UI를 조작하는 선언적인 방법을 제공 → UI를 개별적으로 직접 조작X, 컴포넌트의 상태를 관리.

리액트는 사용자 입력에 반응해서 각 state를 switching함.

 

Declarative(선언형) UI Vs. Imperative(명령형) UI

명령적 vs 선언적

명령적(Imperative)

  • 바닐라 JS에서 작성한 방법
  • JS와 브라우저가 무엇을 해야하는지 단계별로 정확하게 지시해야함
  • 너무 지루하고 복잡한 사용자 인터페이스가 될 수록 너무 어려워짐. → 이미 많이 경험해봤지? ㅋㅋ

선언적(Declarative)

  • 리액트로 작업하는 방법.
  • React.js를 사용할 때는 목표, 즉 화면에 무엇이 표시되어야 하는지를 정의하고 React가 거기까지 도달하는 방법을 알아내도록 만들어야 합니다.
  • 그저 최종 상태를 정의하기만 하면 리액트는 이런것들을 화면에 불러오기 위한 지시사항들을 뒷단에서 생성해줌.

명령형은?

  • Vanila JS로 짠 UI 코드들.
  • 하나하나 직접 다 지정해서 이벤트 조작해줘야함.
  • 개발자들이 신경써야할게 왕 많아지는 거임.
  • 순서대로 해야할 일을 개발자가 직접 하나씩 다 지정해줘야함.

복잡한 시스템에서는 UI를 관리하기가 기하급수적으로 어려워짐. - 새로운 인터렉션, 새로운 UI를 추가하기 위해서는 모든 코드들을 일일이 확인하면서 버그의 발생여부를 파악해야함.

리액트의 선언형

위의 명령형(Vanila) 방식 문제들을 해결하기 위해서 리액트가 만들어졌다. React에서는 직접 UI 조작하지 않고, 화면에 표시할 내용을 그저 선언하기만 하면 React가 UI를 업데이트 해준다.

 

UI를 선언적인 방식으로 생각해보기

  1. Identify: 컴포넌트의 다양한 시각적 상태를 식별합니다.
  2. Determin: 상태 변화를 trigger하는 요소를 파악합니다.
  3. Represent: useState를 사용하여 메모리의 상태를 표현합니다.
  4. Remove: non-essential(비필수적)한 state 변수를 제거합니다.
  5. Connent: 이벤트 핸들러를 연결하여 state를 설정합니다.

Step1. 컴포넌트의 다양한 시각적 상태 식별하기

먼저 리액트에서 state는 CS의 “state machine”에서 나온 state라고 보면 됨.

React는 디자인과 CS의 교차점에 있기에 두 분야에서의 개념들이 섞여있음.

위의 예시의 Form state들을 모두 시각화 해보자.

[ 디자이너의 관점 ]

  • Empty: form의 “Submit”버튼은 비활성화되어 있습니다.
  • Typing: form의 “Submit”버튼이 활성화되어 있습니다.
  • Submitting: form은 완전히 비활성화되어있고 Spinner가 표시됩니다.
  • Success: form 대신 “Thank you”메세지가 표시됩니다.
  • Error: ‘Typing’ state와 동일하지만 추가로 오류 메세지가 표시됩니다.

→ 상태들에 따라 어떤 동작을 하게끔 정의해놓은 state machine이 있다고 생각하자.

export default function Form({
  status = 'empty'
}) {
  if (status === 'success') { // success 상태일땐 이 아래걸 렌더링할거고.
    return <h1>That's right!</h1>
  }

    // success 상태가 아니면 이 아래걸 렌더링 할거다!
  return (
    <>
      <h2>City quiz</h2>
      <p>
        In which city is there a billboard that turns air into drinkable water?
      </p>
      <form>
        <textarea />
        <br />
        <button>
          Submit
        </button>
      </form>
    </>
  )
}

한번에 여러 시각적 상태를 표시하기 → storybook, living styleguide라고 한다!

→ state가 여러개가 있을때, 그냥 모든 state에 대한 모든 UI를 다 보여주는 거임!

→ UI 확인할때 좋을 수 있다!

Step2. 상태 변경을 촉발하는 요인 파악하기

입력(Input) 이라는 것엔 두가지로 나눌 수 있다.

  1. 사람의 입력: 버튼 클릭, 필드 입력, 링크 이동…
  2. 컴퓨터 or 브라우저의 입력: 네트워크에서 응답 도착, 시간 초과, 이미지 로딩, 브라우저의 이벤트 등
    → 두 입력 모두 state 변수를 설정해야 UI를 업데이트 할 수 있음!!
  • 네트워크 Response 성공시, 성공 state로 전환
  • Submit 버튼을 클릭시, 제출중 state로 전환

[ 흐름을 시각화하기 ]

Step3. 메모리의 상태를 useState로 표현하기

[ state 사용하기 ]

  • state는 단순함이 핵심이다!!
  • 가능한 적은 수의 state를 사용해야한다. 만약 많은 state를 사용한다면 버그 확률이 올라간다!
  • 따라서 state를 사용할때는 무조건 필요한 state부터 시작해야한다!
  • 하지만 줄이는 방법이 생각이 안들면 일단~ 필요한거 다 써봐~
const [answer, setAnswer] = useState('');
const [error, setError] = useState(null);
const [isEmpty, setIsEmpty] = useState(true);
const [isTyping, setIsTyping] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
const [isError, setIsError] = useState(false);

Step4. 필요없는 state 삭제하기

위에서 그냥 생각나는대로 다 적은 state들 중에 필요없는 state를 없애는 것이다.

[ state 줄이는 방법 ]

  1. state의 모순점을 찾아보기
    • 동시에 true일 수 없다거나, boolean 조합이 4가지가 가능해야하는데, 3가지가 가능하다거나!Ex 2) isSuccess, isError
    • Ex 1) isTyping, isSubmitting
  2. 다른 state에 이미 정보가 포함되어 있는지 찾아보기
    • 다른 state로 그 state를 검사하고, 확인할 수 있다면 없애버려~
    • Ex2) 다른 state를 뒤집어서 정보를 얻을 수 있을때
    • isError!error 하면 나오는 값임! 없애!
  3. Ex1) isEmptyanswer.length === 0 으로 대체 가능!!
const [answer, setAnswer] = useState('');
const [error, setError] = useState(null);
const [status, setStatus] = useState('typing'); // 'typing', 'submitting', or 'success'

Step5. 이벤트 핸들러를 연결해서 state 설정하기

async function handleSubmit(e) {
    e.preventDefault();
    setStatus('submitting');
    try {
      await submitForm(answer);
      setStatus('success');
    } catch (err) {
      setStatus('typing');
      setError(err);
    }
  }

그저 handler 함수에서 state를 변경만 해준다.

위의 명령형 방식(Vanlia JS)와 비교한다면 정말 엄청나게 코드가 줄어들고, 한눈에 보이는 것을 알 수 있다.