본문 바로가기

나야, 리액트 스터디

[week5] state 관리하기

 

안녕하세요! 물결웹팟 OB 박채연입니다 😞 

 

리액트는 state를 통해 동적인 UI를 쉽게 관리할 수가 있는데요,

그래서 이번주엔 State를 사용해 Input 다루기, State 구조 선택하기, 컴포넌트 간 State 공유하기, State를 보존하고 초기화하기 부분을 읽고, 리액트 state를 다시 정복해보려 합니다 !-!

 

오늘은 제 state가 시들시들해서 호다닥 시작해볼게요 .. 

 


 

 

📍 State를 사용해 Input 다루기

입력 필드의 값은 일반적으로 컴포넌트의 State로 관리합니다!
이를 통해 사용자가 입력한 값을 실시간으로 추적할 수 있고,

양방향 데이터 바인딩을 구현하지 않더라도 React의 단방향 데이터 흐름을 유지할 수 있습니다.

 

입력 필드의 value를 컴포넌트 State에 연결하고,

onChange 이벤트 핸들러를 통해 State를 업데이트하죠!

 

function InputComponent() {
  const [inputValue, setInputValue] = React.useState("");

  const handleChange = (e) => setInputValue(e.target.value);

  return <input value={inputValue} onChange={handleChange} />;
}

 

 

다중 필드 입력을 다루는 경우엔,

입력 필드의 name 속성을 활용해 State를 동적으로 업데이트하고,

다중 입력 필드를 단일 State 객체로 관리하면 코드가 간결해집니다 !

 

function FormComponent() {
  const [formData, setFormData] = React.useState({
    username: "",
    email: "",
  });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData((prevData) => ({
      ...prevData,
      [name]: value,
    }));
  };

  return (
    <form>
      <input
        name="username"
        value={formData.username}
        onChange={handleChange}
        placeholder="Username"
      />
      <input
        name="email"
        value={formData.email}
        onChange={handleChange}
        placeholder="Email"
      />
      <p>Preview: {JSON.stringify(formData)}</p>
    </form>
  );
}

 

 

📍 State 구조 선택하기

State의 구조는 코드의 가독성과 유지보수성에 큰 영향을 미치는데요,
리액트에서는 State를 가능한 간단하고 평평하게(flat) 유지하는 것이 좋다고 합니다!

 

State를 중첩된 객체로 관리하면 불필요한 복잡성이 생길 수 있으니,

필요한 데이터만 State로 관리하고, 계산 가능한 데이터는 State에 포함하지 않습니다.

 

// 중첩된 구조를 피하는 예시
function UserInfo() {
  const [name, setName] = React.useState("");
  const [age, setAge] = React.useState(0);

  // State를 평평하게 유지해 변경 관리가 용이
  return <div>{/* UI 렌더링 */}</div>;
}

 

 

하지만 우리는 ,, 중첩된 state를 사용해야 하는 경우도 있죠!

그럴 땐, 불변성을 유지하며 관리할 수 있도록 해야합니다.

 

State 객체의 중첩된 속성을 업데이트하려면 스프레드 연산자(...)를 사용해 기존 데이터를 복사하는 형태로

불변성을 유지해 리액트의 의 상태 비교 최적화(shallow comparison)가 제대로 작동하도록 해야 합니다.

 

 

function UserProfile() {
  const [user, setUser] = React.useState({
    name: "John Doe",
    address: {
      city: "New York",
      zip: "10001",
    },
  });

  const updateCity = () => {
    setUser((prevUser) => ({
      ...prevUser,
      address: {
        ...prevUser.address,
        city: "Los Angeles",
      },
    }));
  };

  return (
    <div>
      <p>{user.name} lives in {user.address.city}.</p>
      <button onClick={updateCity}>Move to LA</button>
    </div>
  );
}

 

 

 

📍 컴포넌트 간 State 공유하기

애플리케이션이 커질수록 컴포넌트 간 State를 공유해야 하는 경우가 생기는데요,
이때, 공통 조상 컴포넌트(Lifting State Up)에 State를 선언하고, 자식 컴포넌트에 Prop으로 전달해 사용합니다.

 

State를 공유해야 할 컴포넌트들의 가장 가까운 공통 부모 컴포넌트에서 관리하고,

Prop을 통해 데이터를 내려보내며, 데이터 변경 함수를 자식에서 호출합니다.

 

function Parent() {
  const [count, setCount] = React.useState(0);

  return (
    <div>
      <Child count={count} increment={() => setCount(count + 1)} />
    </div>
  );
}

function Child({ count, increment }) {
  return <button onClick={increment}>Count: {count}</button>;
}

 

 

 

 

📍 State를 보존하고 초기화하기

컴포넌트를 다시 렌더링하거나 초기 상태로 리셋해야 하는 경우를 대비해 State를 보존하거나 초기화하는 패턴을 이해해야 합니다.

 

useState 초기값을 함수로 전달하면 초기화 비용을 줄일 수 있고,

상태를 완전히 초기화하려면 부모 컴포넌트에서 상태를 재설정하거나, 상태 업데이트 로직을 잘 설계합니다.

function Counter() {
  const [count, setCount] = React.useState(() => {
    console.log("초기값 계산");
    return 0; // 초기값
  });

  const reset = () => setCount(0);

  return <button onClick={reset}>Reset</button>;
}

 

 

 

정리해보자면, state를 관리할 땐

간단하고 명확하게 유지하기
불변성을 지키기 위해 기존 데이터를 복사 후 업데이트하기
컴포넌트 간 State가 필요하다면 공통 부모에서 관리하기
초기값 및 리셋 로직을 설계해 유지보수를 쉽게 만들기

 

 

컴포넌트 구조와 상태의 복잡성을 최소화하고,

컴포넌트 간 데이터 흐름을 명확히 관리할 수 있도록 노력하는 게 중요할 것 같아요! ☺️

 

 

그럼 마지막으로, 공부하며 든 궁금증 하나 남기겠습니다 !

input 값을 다룰 때마다, input의 value를 console에 찍곤 하잖아요! 그때 무슨 타자를 칠 때마다 console에 값이 우르르르르 변경되는게 보이곤 하는데요, 이걸 보면서 이렇게 state가 자주 바뀌면 성능이 좋진 않겠단 생각이 들곤 했습니다! 그래서 이걸 어떤 식으로 관리해야 좋을지, 또 여러분은 어떤 식으로 관리해왔는지 궁금합니다! 💬

 

모두모두 솝커톤 끝나고 작업하느라 고생 많으셨습니당 ,, 파이팅!