[리액트] 리덕스 정리

Subin·2022년 6월 10일
0
post-thumbnail

리덕스

리덕스는 리액트에서 사용율이 가장 높은 상태관리 라이브러리입니다.
리덕스를 사용하면 컴포넌트 기반인 리액트의 복잡한 구조속에서 보다 간편하게 상태관리가 가능합니다.
리덕스는 리액트 전용이 아니며 바닐라JS등 다른 프레임워크에서도 사용 가능합니다.

주로 사용하는 방식은 아래와 같습니다.

  • 컴포넌트들의 상태 관련 로직들을 다른 파일로 분리해 효율적으로 관리
  • 글로벌 상태 관리

리덕스는 언제 사용하는지?

  • 프로젝트의 규모가 클 때
  • 비동기 작업을 자주 할 때

리덕스 키워드

Action

상태에 어떠한 변화가 필요하게 될 때 액션을 발생시키며 객체 형식으로 이뤄져있습니다.

{
	type: "ACTION_VALUE"
}

액션 객체는 type 필드를 필수적으로 가져야 하며 그 외의 값은 상황에 따라 자유롭게 넣을 수 있습니다.

{
	type: "ACTION_VALUE"
    data:{
    	id: 0,
        text: "리덕스 액션"
    }
}

Action Creator

위의 액션 객체를 가져와 액션을 생성하고 실제 객체로 만들어주는 함수입니다.
단순히 파라미터를 받아와서 액션 객체 형태로 만들어줍니다.

export function addAction(data){
	return{
    	type: "ACTION_VALUE",
        data
    }
}

// 당연히 Arrow Function으로도 가능합니다.
export const addAction = data => ({
	type: "ACTION_VALUE",
    data
});
    

이렇게 액션 생성 함수를 만들어서 사용하는 이유는 컴포넌트에서 쉽게 액션을 발생시키기 위함입니다. 그래서 보통 export 키워드를 사용해 다른 파일에서 불러올 수 있게합니다.

리덕스를 사용할 때 액션 생성 함수가 필수는 아닙니다. 액션을 발생시킬 때마다 액션 객체를 작성할 수도 있습니다.

Reducer

리듀서는 상태에 변화를 일으키는 함수입니다.
현재의 상태와 액션을 인자로 받아 새로운 상태로 업데이트합니다. 즉 만들었던 Action의 임무를 수행할 수 있게 합니다

카운터를 위한 리듀서를 작성한다면 아래 코드와 같습니다.

function Counter(state, action){
	switch(action.type){
    case "INCREASE":
    	return state + 1;
    case "DECREASE":
    	return state - 1;
    default:
    	return state;
    }
}

위와 같이 여러 서브 리듀서를 만들고 이를 합쳐 루트 리듀서를 만드는 형식으로 주로 사용합니다.

Store

스토어는 현재 앱의 상태, 리듀서 및 여러 내장 함수들을 가지고 있습니다.
스토어는 상태를 수시로 확인해 뷰한테 변경된 사항을 알려준다고 생각하면 됩니다.

Dispatch

디스패치는 스토어의 내장 함수 중 하나입니다. 액션을 발생시켜주는 함수라고 이해하시면 됩니다.
dispatch(action) 와 같이 사용하면 스토어가 리듀서 함수를 실행해 디스패치로 넘긴 액션을 처리해 상태를 업데이트 해줍니다.

UseSelector

useSelectore는 Provider로 감싼 store에서 state를 가져올 수 있게 해줍니다.
subscription 하도록 도와준다. 즉, 상태 값이 변경되면 업데이트 하고 re-rendering 할 수 있도록 도와 줍니다.

최적화

랜더링 될 때마다 state가 바뀌지 않아도 렌더링을 합니다. 최적화 방법이 2가지 있는데
첫 번째로 useSelector를 여러번 사용하면 값이 하나라도 바뀔 때 리렌더링 해줍니다.

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

두 번째는 shallowEqual함수를 useSelector의 두번째 인자로 전달해주는 것 입니다.

const { number, diff } = useSelector(
   state => ({
     number: state.counter.number,
     diff: state.counter.diff
   }),
   shallowEqual
 );

useSelect의 두번째 파라미터는 equalityFn 입니다

equalityFn?: (left: any, right: any) => boolean

이는 이전 값과 다음 값을 비교하여 true가 나오면 리렌더링을 하지 않고 false가 나오면 리렌더링합니다.

Subscribe

구독 또한 스토어의 내장 함수 중 하나입니다.
액션이 디스패치될 때 마다 함수를 호출하는 기능을 합니다.
예를 들어 유튜브 구독하기를 누르면 해당 유튜버가 글을 올릴 때 알림이 뜬다고 생각하면 된다.

리덕스의 3가지 규칙

1. 하나의 앱에는 하나의 스토어

하나의 앱에서는 단 한개의 스토어를 사용해야 합니다. 여러개의 스토어를 사용할 수 있긴 하지만 권장되는 방법이 아닙니다. (특정 업데이트가 빈번하게 일어나거나 앱의 특정 부분을 분리시킬 때 사용되긴 합니다.)
또한 여러개의 스토어를 사용하면 개발 도구를 사용하지 못합니다.

2. 상태는 읽기 전용

리액트에서는 state 업데이트 할 때 setState를 사용하고, 배열을 업데이트 할 때는 concat과 같은 함수를 사용해 기존의 배열을 수정하지 않고 새로운 배열을 만들어 교체하는 방식으로 업데이트합니다. 객체를 업데이트 할 때도 Object.assign을 사용하거나 spread 연산자를 사용해 업데이트를 합니다.

리덕스에서도 마찬가지로 기존의 상태는 건들이지 않고 새로운 상태를 생성해 업데이트 해줍니다.
나중에 개발자 도구를 통해 이전 값을 다시 가져올 수 있는 이점도 있습니다.

이 불변성을 유지해야 하는 이유는 내부적으로 데이터가 변경되는걸 감지하기 위해 shallow equalty 검사를 하기 때문입니다. 이를 통해 깊숙히 비교하는 것이 아닌 겉핥기 식으로 비교하게 되어 좋은 성능을 유지 할 수 있기 때문입니다.

3. 리듀서는 순수한 함수

  • 리듀서는 이전 상태와 액션을 파라미터로 받습니다.
  • 이전의 상태는 절대로 건들이지 않고, 변화를 일으킨 새로운 상태 객체를 만들어 반환합니다.
  • 똑같은 파라미터로 호출된 리듀서는 언제나 똑같은 retrun을 반환해야만 합니다.

여기서 3번째의 동일한 인풋이라면 언제나 동일한 아웃풋이 있어야 한다는데 일부 new Date()같이 실행 할 때 마다 다른 결과값이 나타나는데 이는 순수하지 않은 작업이므로 리덕스 미들웨어를 사용합니다.

profile
고양이가 세상을 지배한다.

0개의 댓글