ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 🍾 React의 상태관리 툴 맛보기! : redux, recoil, react query
    SOJU 2기 🍾 2023. 7. 3. 16:26

     

     

    상태관리 툴을 사용하는 이유?

    React로 웹 애플리케이션을 만들 때 개발자는 수많은 컴포넌트들을 만들어내고, 컴포넌트들은 부모-자식 관계가 생긴다. 이때 내가 원하는 데이터를 내가 원하는 컴포넌트까지 보내주기 위해서는 부모->자식->자식->자식... 혹은 자식->부모->부모->... 식으로 수~많은 부모 혹은 자식 컴포넌트를 연결시켜주지 않으면 안 되는 상황을 마주하게 된다. 

    React는 props를 통해 데이터를 연결시켜주는데 앱이 복잡하고 커질수록 이게 도대체 어디서부터 시작된 데이터인지 알기 힘들어진다. 그때 사용하는 게 바로 상태관리 툴이다. 끝없이 이어진 컴포넌트들을 연결, 연결, 연결... 하는 방법이 아니라 내가 원하는 데이터를 내가 원하는 컴포넌트에서 사용할 수 있게 해 준다. 

     

    상태관리 툴의 종류

    상태관리 툴은 정말~ 많지만 이번 주 스터디 과제로 접하게 된 건 제목에 써있는 세 개의 상태관리 툴이다.

    redux, recoil, react query 순으로 공부한 내용 등을 기록해둔다. 

     

    ✍️ Redux (+react redux)

    🔗 공식 문서

    🔗 참고 강의 영상

     

    ✨ 설치

    npm install redux react-redux

    redux, react-redux 를 함께 설치해서 사용한다.

     

    ✨ store, reducer, action

    import {createStore} from ‘redux’;
    
    function reducer(currentState, action) {
    	if(currentState === undefined) {
    		// 찾을 수 없을 때는 기본값을 리턴한다.
    		return {
    			number:1;
    		}
    	}
        
    	const newState = {…currentState};
        // redux는 각각의 state의 변화를 불변하게 유지해야한다 때문에 새로운 스테이트(과거 state 복제본)를 만든다.
    
    	if(action.type === ‘PLUS’) {
    		newState.number++;
    	}
    	return newState;
    }
    
    const store = createStore(reducer);

     

    - store

    Redux store는 앱을 구성하는 상태, 액션, 리듀서를 한데 모아 제공한다. 

    주의할 점은 어플리케이션에는 하나의 store만 존재할 수 있다는 점이다. 

     

    - action

    store 안에 있는 state (= 즉, currentState)를 어떻게 바꿀 것인가를 정의한다.

    예제코드에서 보이는 action.type의 의미는 action의 type이 PLUS 일 때 다음 동작을 실행한다는 의미이다.

    type을 설정할 때는 dispatch를 이용한다. 이는 뒤에서 조금 더 살펴보자.

     

    - reducer

    이전의 state(=currentState)와 설정한 action을 합쳐서 새로운 state(= newState)를 만들어준다.

    예제코드를 보면 더 쉽게 확인할 수 있다. reducer라는 함수에 이전의 state(= currentState)와 action을 함께 인수로 넣어주고 있다. 

     

    ✨ react redux 4인방!

    redux의 주요 3인방 store, action, reducer 가 있다면 react redux에는 주요 4인방이 있다.

    Provider, useSelector, useDispatch, connect

    이다.

     

    - Provider

    state들을 어떤 component들에게 제공할 것인가. 가장 바깥쪽의 울타리를 정의한다. 

    <Provider store={store}>
    	<Component1 />
    	<Component2 />
    	<Component3 />
    	<Component4 />
        ...
    </Provider>

    예제 코드와 같이 컴포넌트들을 감싸준다. 감싸진(?) 컴포넌트들은 store를 사용할 수 있게 된다.

     

    - useSelector

    const number = useSelector(state => state.number);

    끝없는 부모자식 관계를 거쳐야 하는 게 아니라, 내가 원하는 컴포넌트에 바로 연결할 수 있다. (마치 무선! 블루투스!)

     

    - useDispatch

    const dispatch = useDispatch();
    onClick = {() => {
    	dispatch({type: ‘PLUS’})
    }}
    // PLUS라는 액션을 전달했다. -> reducer가 호출된다

    위에서 잠깐 언급했던 dispatch를 위해 사용한다.

    원하는 type명을 설정할 수 있다.

     

     

     


     

     

     

    ✍️ recoil

    🔗 공식문서

    🔗 참고 컨퍼런스 영상

     

    ✨ 설치

    npm install recoil

     

     대표적 특징?

    • React 내부상태만을 이용한다.
    • 작은 atom 단위로 관리한다. 
    • 순수함수인 Selector를 이용하여 데이터를 가공 혹은 다른 상태를 구독한다.
    • re-render를 최소화한다.
    • 새로운 react 기능과 호환성이 높다.

     

    ✨ 사용법

    - RecoilRoot

    import React from 'react';
    import {
      RecoilRoot,
      atom,
      selector,
      useRecoilState,
      useRecoilValue,
    } from 'recoil';
    
    function App() {
      return (
        <RecoilRoot>
          <CharacterCounter />
        </RecoilRoot>
      );
    }

    recoil을 사용하는 컴포넌트는 RecilRoot으로 감싸주어야 한다. 

     

    - Atom 

    const textState = atom({
      key: 'textState', // unique ID (with respect to other atoms/selectors)
      default: '', // default value (aka initial value)
    });

    사실 읽어도 들어도 잘 이해가 되지 않았는데 store과 유사한 개념이라고 생각하면 된다고 들으니 그제야 이해가 됐다.

    atom 값을 읽는 모든 컴포넌트들은 atom이 변경되었을 때 re-render 된다. 

    function CharacterCounter() {
      return (
        <div>
          <TextInput />
          <CharacterCount />
        </div>
      );
    }
    
    function TextInput() {
      const [text, setText] = useRecoilState(textState);
    
      const onChange = (event) => {
        setText(event.target.value);
      };
    
      return (
        <div>
          <input type="text" value={text} onChange={onChange} />
          <br />
          Echo: {text}
        </div>
      );
    }

    atom 을 읽고 쓰게 하기 위해서는 useRecoilState()를 사용한다. 

     

    - Selector

    Selector는 파생된 상태(derived state)의 일부를 나타낸다. 파생된 상태는 상태의 변화다. 파생된 상태를 어떤 방법으로든 주어진 상태를 수정하는 순수 함수에 전달된 상태의 결과물로 생각할 수 있다. - 공식문서
    const charCountState = selector({
      key: 'charCountState', // unique ID (with respect to other atoms/selectors)
      get: ({get}) => {
        const text = get(textState);
    
        return text.length;
      },
    });
    
    
    function CharacterCount() {
      const count = useRecoilValue(charCountState);
    
      return <>Character Count: {count}</>;
    }

    get 프로퍼티를 사용해서 textState를 가공, text.length를 받아올 수 있다. 

    +) useRecoilState(get/set), useRecoilValue(get)/useSetRecoilValue(set)...

     

     

     


     

     

     

    ✍️ React Query

    왜 TanStack Query!? 하고 당황했지만 이름이 바뀌었다고 한다 🤓 ...

    🔗 공식문서

    🔗 참고 강의 영상

     

    React Query?

    서버에서 가져온 데이터를 브라우저 앱에서 사용하기 쉽도록 도와주는 라이브러리이다.

     

    server state / client state

    - server state

    클라이언트가 요청하면 -> 서버는 데이터베이스의 유저 정보 값을 가져와 server state 값을 만들어낸다.

    이때 데이터베이스에 있는 값을 '그대로' 전달하거나 요청에 담긴 특정 값을 이용해 정보를 가공하여 메모리에 들고 있는다 -> 이를 클라이언트에 전달하는 방식이다. 

     

    - client state

    두 가지로 나눌 수 있다.

    1. 클라이언트에서 자체적으로 만드는 state (최초발생지 : 클라이언트)
    2. 서버에서 전달받은 값으로 만드는 state (최초발생지 : 서버)

    1의 경우, 대개 UI를 담당하는 부분을 일컫는다. (예: 모달창 오픈/클로즈, 어떤 버튼이 클릭되었는가, 창이 리사이징 되고 있는가 .. 등 UI와 관련된 정보(메타 정보)를 담은 값)

     

    2의 경우, useState를 사용한다는 가정 하에 데이터를 불러와 setState 호출을 통해서 응답 당시의 server state를 component state로 wrapping 한다. 

     

    => 즉, 클라이언트 앱은 server state와 client state에 대한 로직 처리를 나누어서 선언해주어야 한다. 

     

    왜 React Query?

    리액트쿼리는 hook기반 로직들로 되어 있어서 해당 훅을 사용하는 컴포넌트에서 상태 값의 변경을 간편하게 파악, 리렌더링을 유발하게 해 준다. 또한 리액트쿼리는 데이터의 캐시 처리를 간편하게 있는 인터페이스를 제공한다.

    • 몇 초 이후에는 데이터가 유효하지 않은 것으로 간주하고 데이터를 다시 불러온다.
    • 데이터에 변경점이 있는 경우에만 리렌더링을 유발한다.
    • 유저가 탭을 이동했다가 다시 돌아왔을 때 데이터를 다시 불러온다.
    • 데이터를 다시 호출할때 응답이 오기 전까지는 이전 데이터를 계속 보여준다. 필요에 따라서는 로딩바와 같은 대안 UI 보여주기 위해 loading state 기본적으로 제공한다.
    • 무한스크롤!

     

    ✨ 설치

    npm i @tanstack/react-query

     

     

     

     

     

     

    댓글

Designed by Tistory.