useState 올바르게 사용하기


useState

💡 state란?

필자는 이전까지, 그냥 state는 자주 변동되는 값을 담는 그릇이라고만 생각해왔었다.

하지만, React를 계속 사용하다 보니 state에 대한 피상적 이해만으로는 React를 깊게 이해하고 개발을 하는데 무리가 있다는 판단이 들어 state를 다시 정리해보고자 한다.

state의 정의

state는 값이 계속 변경되는 동적 데이터로, 컴포넌트 간의 상호작용을 담당하기도 한다. 또한, state의 값이 변경되면 컴포넌트는 리렌더링 된다.

state가 되기 위한 조건

우선, 모든 학습에 앞서 state가 무엇인지에 대한 명확한 이해가 필요하다..!!

그렇다면 state란 무엇일까? 아래의 질문들에 직접 답변을 해보자 (해당 질문에 state가 포함 되는지).

  1. state 데이터가 계속 변동되는가?
  2. 부모로부터 전달 받은 props인가?
  3. 특정 state로부터 어떠한 계산을 통해 도출되는 데이터인가?

결론부터 얘기하자면 정답은 OXX다.

  1. state는 정적 데이터가 아닌, 동적 데이터다. 따라서 변하지 않고 고정된 데이터를 state로 활용하는 것은 옳지 않다. 정적 데이터는 const에 상수로써 담아 활용하는 것이 옳다고 할 수 있다.

  2. 부모로부터 전달 받은 propsprops일 뿐이다. state는 하나의 컴포넌트 안에서 관리되는 데이터로, state를 사용할 때는 관리 및 사용하는 컴포넌트(부모)와 이를 활용하는 컴포넌트(props로 받아 활용하는 자식 컴포넌트)로 철저히 분리하여 사용해야 한다.

  3. 우리는 중복배제 원칙을 항상 생각하며 state의 최소집합을 고려해야 한다. 아래의 예시를 보자.

    1
    2
    const [todos, setTodos] = useState([]);
    const [todoCount, setTodoCount] = useState(0);

    이는 효율적이지 못한 state 활용 방식이다. 굳이 todoCount라는 state를 생성하지 않아도 우리는 todos.length 등을 활용해 해당 값을 언제든지 구할 수 있다. 그냥 아래와 같이 꼭 필요한 state만 활용해보는게 어떨까? 불필요한 리렌더링을 방지하자!

    1
    2
    const [todos, setTodos] = useState([]);
    const todoCount = todos.length;

🤷🏻‍♂️ state와 props의 차이점

props vs state

propsproperty의 줄임말로, state와 언뜻 보기에는 비슷하지만 분명한 차이점을 보유한다.
물론 state와 동일하게 props가 변경되면 컴포넌트는 리렌더링 된다.

  1. props는 컴포넌트 간에 전달되는 데이터다.

    즉, 함수 안의 매개변수, 인자와 같은 역할을 하는 것이다. 반면, state는 함수 안에서만 활용되는 ‘함수레벨 스코프’의 변수이자 Javascript 객체와 같다고 볼 수 있다.

  2. props는 변경될 수 없다.

    statesetState를 통해 컴포넌트 내에서 언제든지 변경될 수 있다. 하지만 props는 ‘읽기 전용’으로, 참조만 할 뿐 직접적으로 이를 변경할 수는 없다. 위에서 설명한 관리자 vs 사용자가 명백히 구분되어 있다는 것이 이를 의미한다.


✨ useState를 올바르게 사용하는 방법

  1. state를 통해 계산될 수 있는 값은 굳이 useState()에 담지 않아도 된다.

    위에서 설명했듯, 기존의 state를 통해 계산될 수 있는 값이라면, 그냥 상수 또는 변수로써만 사용해도 충분하다.

  2. setState()useEffect 내에서 비동기적으로 사용될 경우, state로 사용하지 않는다.

    굉장히 중요한 진리와도 같은 제언이다. 아래의 예시를 봐보자.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    const [product, setProduct] = useState(null);
    const [price, setPrice] = useState(null);

    useEffect(() => {
    const fetcher = async () => {
    const result = getProduct();
    setProduct(result);
    };
    fetcher();
    }, []);

    useEffect(() => {
    if (product) {
    setPrice(getPrice(product));
    return;
    }
    }, [product]);

    이 경우, useEffect가 두 번 쓰였다. 컴포넌트가 렌더링 됐을 때 productutils의 유틸함수에서 받아오고, product가 존재하면 setPrice를 통해 price가 업데이트 된다.

    근데… 그냥 이렇게 사용하면 되지 않을까?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const [product, setProduct] = useState(null);
    const price = product && getPrice(product);

    useEffect(() => {
    const fetcher = async () => {
    const result = getProduct();
    setProduct(result);
    };
    fetcher();
    }, []);

    즉 이는 위에서 설명한 1번 조건과도 연결이 되는 것이다. product라는 state의 유무에 따라 price값이 정해져야 하는 것인데, 이는 충분히 product라는 state 하나만으로도 구현할 수 있기에 굳이 price라는 state를 하나 더 만들 필요가 없는 것이다.


포스팅에 참고한 자료

react-guide/props-vs-state.md at master · uberVU/react-guide

Lucy | ReactJS: Props vs. State

useState 과도하게 사용하지 않기


useState 올바르게 사용하기

https://hoonjoo-park.github.io/react/2.useState/

Author

Hoonjoo

Posted on

2022-02-02

Updated on

2022-02-07

Licensed under

Comments