React, Redux, 그리고 Recoil

최준영·2021년 5월 27일
0

개념정리

목록 보기
1/2
post-thumbnail

개요

이번에 redux 와 recoil에 대해서 연구해볼 기회가 생겨서 간단하게 정리하고자 글을 쓴다. 개인적으로는 한번도 react도 쓴 적이 없기에 정말 기본적인 내용부터 알아야 했고, 나와 같은 사람들이 있고 react가 어떤건지 알고 싶은 사람들이 있다면 도움이 되고자 써본다.

상태관리(State Management)의 필요성

React 에서는 컴포넌트(Component) 라는 요소가 있고, 이 요소는 두가지 속성값, props 와 state을 가지고 있는데 컴포넌트의 state에 따라서 페이지에 보여지는게 바뀌고, 컴포넌트이 소통할 때 props를 주고 받는다. 다만 React 에서 컴포넌트들의 관계는 단방향의 Tree 형태이기에, props는 부모에서 자식 컴포넌트로만 보낼 수가 있고, 자식들 간의 소통을 위해서는 자식의 상태를 부모로 올려줘서 부모 컴포넌트가 함수를 props에 넣어서 내려주는 식의 구조가 필요하다. 이럴 경우, 그 부모 아래에 있는 모든 컴포넌트들이 새롭게 Render이 되는데, 이것은 컴포넌트들이 각자 따로 반응해서 Render 된다는 리액트의 장점을 무효화 시키는 문제가 된다.

또한 컴포넌트들이 많아 지고 Tree 구조가 복잡해질수록 멀리 떨어진 자식 컴포넌트 사이의 소통을 props만을 이용해서 소통하기에는 지나치게 복잡하고 문제가 발생 시, 원인 파악도 힘들어진다. 이를 해결하기 위해서 props를 주고 받는 것 이외에 컴포넌트들의 상태를 관리하기 하는 방법이 필요하다.

아래 사진에서는 Redux 라는 상태관리 라이브러리를 사용하는걸 보여준다. Redux 가 없이 기본 리액트로 멀리 떨어진 컴포넌트들 끼리 소통하려면 굉장히 복잡하지만, Redux를 사용하면 효율적이고 간단한걸 볼 수 있다.


이미지 1. Redux의 유무에 따른 상태 변화의 차이

Redux

Redux는 기존 리액트에서 상태관리를 더욱 수월하게 하기 위해서 만들어진 라이브러리로, Store, Reducer, Action와 같은 요소들이 추가된다.

  • Store는 위의 이미지에서 나오듯이 앱의 state을 전체적으로 관리한다. Store 안에 있는 값이 바뀌면 앱이 그것에 맞게 새로 업데이트가 된다.
    • Store 안에 있는 state들을 모두 갱신하기 위해서는 store.dispatch()를 호출해야한다. store.dispatch()가 호출되면, store은 reducer를 호출해서 state의 값들을 새롭게 변경한다.
    • Store 안에 있는 state을 받기 위해서는 store.getState()을 호출할 수 있다.
  • Selectors는 store에서 state을 읽을 때, 특정 값들을 가져오는 함수들이다. 아래의 예시에서는 state 안에 있는 value 값을 가져온다.
  const selectStateValue = state => state.value
  const currentValue = selectStateValue(store.getState())
  • Reducer는 이벤트가 발생 할 경우, 기존의 State와 이벤트에 를 받아서 Store 안의 State을 새롭게 바꿔주는 함수다. Redux에서 Reducer만 Store안에 있는 State들을 바꿔줄 수 있다.
  • Action은 Reducer가 받는 이벤트로, Store을 어떻게 바꿔줄지 정해주는 변수이다. 예를 들어 Action이 Add인지 Subtract 인지에 따라서, Reducer가 Store 안에 있는 값을 증가 시키거나 감소 시킬 수 있다.

기존 리액트의 상태 관리가 어려운 이유 중 하나는 컴포넌트들이 단방향으로 소통하기 때문에 State의 공유가 어렵다는 점이었는데 Redux는 이러한 공유하는 State 들을 Tree 구조 바깥에 있는 Store 라는 곳에 모으는 방법으로 해결한다. 또한, 각각의 컴포넌트들이 Store에 Subscribe를 함으로써, Store 안에 있는 State가 바뀔 경우, 그 State을 구독하는 컴포넌트만 새롭게 Render하게 된다. 이로써 리액트의 장점이었던, 컴포넌트들이 따로 Render된다는 장점을 살릴 수 있게 해준다.

Recoil

Recoil 또한 Redux와 마찬가지로 기존 리액트의 상태관리의 한계를 해결하기 위한 라이브러리로, Atom 과 Selector 두 개의 중요 요소들이 추가된다.


이미지 2. Recoil에서 쓰이는 Atom

  • Atom는 특정 컴포넌트에 묶여있지 않고, 컴포넌트들이 구독/갱신이 가능한 state 이다. 아래와 같이 만들 수 있다
  const healthPointState = atom({
      key: 'healthPoint',
      default: 100,
  });
  • 함수 혹은 컴포넌트에서 이 state를 읽고 싶다면, useRecoilState Hook을 이용해서 가져올 수 있다. 아래의 코드에서 버튼을 누르면, 텍스트에 표시된 숫자가 줄어들게 된다.
    function healthPointDisplay() {
      const [healthPoint, setHealthPoint] = useRecoilState(healthPointState);
      return (
        <p> Remaining Health: {healthPoint} </p>
        <button onClick={() => setHealthPoint((healthPoint) => healthPoint - 1)}>
          Click to Decrease
        </button>
      );
    }
  • Selector는 Atom 혹은 다른 Selector를 입력 받는 함수이다. 입력 받은 Atom이나 Selector의 값이 바뀔 경우, Selector함수도 갱신 된다. 예를 들어, 아래에 Selector를 이용해서 숫자 값을 가지고 있는 Atom값을 String 형태로 가지고 있을 수 잇다.
    • 아래 코드에서 만약 healthPointState Atom의 값이 100이라면 Selector는 "100pt"를 반환하고, Atom의 값이 80으로 줄어들면 Selector도 값을 "80pt" 로 갱신된다
 const healthPointText  selector({
   key: 'healthPointText',
   get: ({get}) => {
     const healthPointValue = get(healthPointState);
     const unit = 'pt';

     return `${healthPointValue}${unit}`;
   }
 })

이상 글을 마무리 짓는데, 나도 생소한 주제이고 나름 정리해 놓은 글이기에 잘못된 점이 있다면 댓글에 지적해주면 감사할 것 같다


사진 출처
이미지 1.
이미지 2.

profile
다양하게 이것저것 배우는 개발자입니다.

0개의 댓글