redux, recoil 내용 정리

katanazero·2021년 7월 5일
20

react

목록 보기
9/15
post-custom-banner

redux 와 recoil 은 무엇이 다른가

  • 최근에 상태관리라이브러리들이 많고, 그 개념들도 다르다. 그래서 정리를 하고자 작성

redux 및 recoil 은 react 를 위한 상태관리(state management) 라이브러리
redux 는 Flux 아키텍쳐 기반
recoil 은 Atomic 모델 기반(Atom 이라는 작은 상태 단위로 관리하고 Atom 을 결합하여 데이터를 가공)


  • flux 아키텍쳐의 데이터 흐름은 단방향이다.
  • Action 은 Action 을 생성 하여(type, payload) 이를 Dispatcher 에게 전달
  • Dispatch 는 모든 Action 을 전달받아 Store 에 전달을 해준다
  • Store 는 State 를 가지고 있고 State 를 변경해준다
  • Store 에서 State 변경 시, change 이벤트가 발생하면서 View 에게 State 가 변경되었다는걸 알려준다.(이때 View 에서 사용하는 State 는 업데이트가 일어난다 -> Rerender)

redux 는 중앙집중식으로 상태관리가 이루어진다. 실제로 전체 모델은 그렇게 복잡한편은 아니다.

// action types
export const UPDATE_NAME = `UPDATE/NAME`;

// action creator function
export const updateNameAction = name => ({type: UPDATE_NAME, payload: {name}});


// state
const initialState = {
    name: '',
};

// reducer
const reducer = (state = initialState, action) => {

    switch (action.type) {
        case UPDATE_NAME :
            return {
                ...state,
                name: action.payload.name,
            }
        default :
            return state
    }
};

export default reducer
// store.js

import {combineReducers, createStore} from 'redux';
import testReducer from  './modules/test/index';

const rootReducer = combineReducers({
    testReducer
});

const store = createStore(rootReducer);

export default store
// index.js


import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

// redux
import store from './store/index';
import {Provider} from 'react-redux'

ReactDOM.render(
    <React.StrictMode>
        <Provider store={store}>
            <App/>
        </Provider>
    </React.StrictMode>,
    document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
// component

import React, {useEffect} from "react";
import {useSelector, useDispatch} from "react-redux";
import {
    updateNameAction,
} from "../../store/modules/test";

export default function TestComponent() {

    const dispatch = useDispatch();
    const nameState = useSelector(state => state.testReducer.name);
  
    const dispatchUpdateName = (name = 'basic') => {
        dispatch(updateNameAction(name)); // action
    };
   

    useEffect(() => {
        dispatchUpdateName();
    }, []);

    return (
       <div>
        <p>{nameState}</p>
       </div>
    )
}

redux 를 사용하기 위해서는 전체앱에 감싸야한다.
사용할 state 는 하나씩 해야한다. 만약 객체를 하는경우에는 성능이슈가 발생(매번 새로운 객체를 생성하기 때문)
useSelector() 훅같은 경우 두번째 인자로 react-redux 패키지에서 제공하는 shallowEqual 함수 전달이 가능하며 이전값과 다음값을 비교하는데 얕은 비교를 함
useSelector(selector: Function, equalityFn?: Function)
equalityFn?: (prev: any, next: any) => boolean
false 인 경우 rerender true 인 경우 rerender 하지 않음
이러한 비교연산은 BF(Brute Force) 방식으로 진행하므로 객체 키값들이 많으면 성능적으로 좋지 않고 하나하나 직접 작성하는거도 번거로움
파생된 상태(상태 계산)는 reselect 패키지에 의존해야 합니다.


// 상태 가공 or 상태 계산
const greet = useSelector(state => {
      return `${state.testReducer.name} Hello! (`${new Date().toISOString()}`
)`;
});
  • action 이 발생하여 store 가 업데이트 되면, 실제 name 값이 변경되지 않았어도 위 연산을 계속해서 처리함(배열이나 객체같은거 처리할수록 비용이 커짐) -> new Date 찍히는값이 계속해서 바뀔거다. 이는 해당 testReducer 가 업데이트가 일어나지 않아도 마찬가지..(다른 상태를 쓰고있다면 컴포넌트가 렌더링이 일어나고 컴포넌트가 렌더링될때 useSelector() 를 호출)

  • recoil 은 다른 개념을 제시함. Atom 이라는 상태 단위로 상태를 관리하며 컴포넌트는 이 Atom 을 구독하기만 하면 됨.
  • 저장소 개념보다는 작은 상태 단위(Atom)로 관리
  • recoil 은 redux 와 비교했을때 학습곡선 비용이 적으며 동시모드를 지원
  • 상태 변경으로 인한 불필요한 렌더링이 발생하지 않음(상태를 구독한 컴포넌트만 리랜더링 발생)
  • selector 를 통해 캐싱(기본적으로 값을 캐싱함)

아톰(atom) : 데이터 조각 or 상태 조각
셀렉터(selector):
1. 아톰에서 파생된 데이터 조각
2. 데이터를 반환하는 순수 함수


결론

recoil 은 redux 와 비교했을때 적은 학습곡선을 가지고 있고, 코드량도 recoil 이 훨씬 적다
recoil 은 devTools 등 아직 부족한 부분이 많다(현재 버전은 0.3.1)
recoil 은 성능이점을 얻을 수 있으나, 대규모 프로젝트에 적용하기에는 좋은 사례라던가 레퍼런스들이 부족

profile
developer life started : 2016.06.07 ~ 흔한 Front-end 개발자
post-custom-banner

0개의 댓글