state 구조 선택

홍준섭·2023년 6월 8일

react

목록 보기
24/29

state 구조화 원칙

그룹관련 상태

항상 두 개 이상의 state 변수를 동시에 업데이트하는 경우 단일 state변수로 병합하는 것이 좋다

const [x, setX] = useState(0);
const [y, setY] = useState(0);

같이 업데이트 하는 경우 이러한 형태보다는

const [position, setPosition] = useState({ x: 0, y: 0 });

이러한 형태가 낫다

state의 모순을 피해라

여러 state가 모순되고 동의하지 않는 방식으로 state가 구조화 되면 실수할 여지가 생긴다.

import { useState } from 'react';

export default function FeedbackForm() {
  const [text, setText] = useState('');
  const [isSending, setIsSending] = useState(false);
  const [isSent, setIsSent] = useState(false);

  async function handleSubmit(e) {
    e.preventDefault();
    setIsSending(true);
    await sendMessage(text);
    setIsSending(false);
    setIsSent(true);
  }

  if (isSent) {
    return <h1>Thanks for feedback!</h1>
  }

  return (
    <form onSubmit={handleSubmit}>
      <p>How was your stay at The Prancing Pony?</p>
      <textarea
        disabled={isSending}
        value={text}
        onChange={e => setText(e.target.value)}
      />
      <br />
      <button
        disabled={isSending}
        type="submit"
      >
        Send
      </button>
      {isSending && <p>Sending...</p>}
    </form>
  );
}

// Pretend to send a message.
function sendMessage(text) {
  return new Promise(resolve => {
    setTimeout(resolve, 2000);
  });
}

이렇게 하는 경우 isSending과 isSent가 동시에 true가 되는 모순적인 상황이 발생할 가능성이 있다.
그렇기에

import { useState } from 'react';

export default function FeedbackForm() {
  const [text, setText] = useState('');
  const [status, setStatus] = useState('typing');

  async function handleSubmit(e) {
    e.preventDefault();
    setStatus('sending');
    await sendMessage(text);
    setStatus('sent');
  }

  const isSending = status === 'sending';
  const isSent = status === 'sent';

  if (isSent) {
    return <h1>Thanks for feedback!</h1>
  }

  return (
    <form onSubmit={handleSubmit}>
      <p>How was your stay at The Prancing Pony?</p>
      <textarea
        disabled={isSending}
        value={text}
        onChange={e => setText(e.target.value)}
      />
      <br />
      <button
        disabled={isSending}
        type="submit"
      >
        Send
      </button>
      {isSending && <p>Sending...</p>}
    </form>
  );
}

// Pretend to send a message.
function sendMessage(text) {
  return new Promise(resolve => {
    setTimeout(resolve, 2000);
  });
}

isSending과 isSent가 동시에 있어서는 안되므로 typing, sending, sent 중 하나의 state를 취할수 있는 상태 변수로 바꾸는 것이 좋다

중복 상태 방지

렌더링 중 component의 props 또는 기존 state변수에서 일부 정보를 계산할 수 있는 경우 해당 정보를 해당 component의 state에 입력하면 안된다.

import { useState } from 'react';

export default function Form() {
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');
  const [fullName, setFullName] = useState('');

  function handleFirstNameChange(e) {
    setFirstName(e.target.value);
    setFullName(e.target.value + ' ' + lastName);
  }

  function handleLastNameChange(e) {
    setLastName(e.target.value);
    setFullName(firstName + ' ' + e.target.value);
  }

  return (
    <>
      <h2>Let’s check you in</h2>
      <label>
        First name:{' '}
        <input
          value={firstName}
          onChange={handleFirstNameChange}
        />
      </label>
      <label>
        Last name:{' '}
        <input
          value={lastName}
          onChange={handleLastNameChange}
        />
      </label>
      <p>
        Your ticket will be issued to: <b>{fullName}</b>
      </p>
    </>
  );
}

위의 경우 fullName은 firstName과 lastName을 통해 렌더링 중에 항상 계산할 수 있으므로 state에서 제거해야 한다.

state에서 중복을 피하라

동일한 데이터가 여러 state간에 또는 중첩된 객체내에 중복되면 동기화를 유지하기 어렵다.

깊게 중첩된 state 피하기

상태가 너무 중첩되어 쉽게 업데이트할 수 없는 경우 평평하게 만드는 것이 좋다.

profile
개발 공부중입니다

0개의 댓글