REDUX-REACT

y0ung·2021년 3월 12일
0

Redux

목록 보기
2/2
post-thumbnail

리덕스 패턴

가장 많이 사용하는 패턴은 프레젠테이셔널 컴포넌트와 컨테이너 컴포넌트를 분리 하는 것이다.

  • 프레젠테이셔널컴포넌트 : 컨테이너 컴포넌트에서 props를 받아서 화면에 UI를 보여주기만 한다.

  • 컨테이너 컴포넌트 : 리덕스와 연동되어 있는 컴포넌트로, 리덕스로부터 상태를 받아오기도 하고 리덕스 스토어에 액션을 디스패치 하기도 한다.

React에 redux 적용하기

1.설치

$ npm i redux react-redux

2. 폴더 구조

src/modules

액션타입, 액션 생성 함수, 리듀서 함수를 기능별로 파일 하나에 몰아서 작성하는 방법을 선호한다. 위와 같은 구조 방식을 Ducks 패턴이라고 한다.

3.모듈생성하기

modules/counter.js

액션 타입

  • 대문자로 정의
  • 문자열 내용은 '모듈이름/액션 이름' 형태로 작성

리듀서함수 -> counter

리듀서 함수에는 현재 상태를 참조하여 새로운 객체를 생성해서 반환한다.

4. 루트 리듀서 만들기

스토어를 만들때(createStore()) 하나의 리듀서만 필요하므로 여러개의 리듀서들을 합쳐야 한다.

modules/index.js

5. 스토어 생성하기

src/index.js

컨테이너 컴포넌트 생성하기

src/containers

컴포넌트를 리덕스와 연동하려면 react-redux에서 제공하는 connect 함수를 사용해야 한다.

connect()

connect(mapStateToProps, mapDispatchToProps)(연동할 컴포넌트)
  • mapStateToProps : 리덕스 스토어 안의 상태를 컴포넌트의 props로 넘겨주기 위해 설정하는 함수

  • mapDispatchToProps : 액션 생성 함수를 컴포넌트의 props로 넘겨주기 위해 사용하는 함수

적용해보기

src/containers/CounterContainer.js

dispatch 간결화 하기

컴포넌트에서 액션을 디스패치하기 위해 각 액션 생성 함수를 호출하고 dispatch로 감싸는 작업이 번거로울수 있다. 특히 액션 생성 함수의 개수가 많아질경우 더더욱 그럴 것이다. 이럴때 사용하는 방법 들을 살펴보자.

1. bindActionCreators()
bindActionCreators : 리덕스에서 제공하는 유틸 함수이다.

2. 객체화

리덕스를 더 편하게 사용

1. redux-actions

설치하기

$ npm i redux-actions

  • createAction : 액션 생성 함수 작성
export const potatoName = createAction(액션타입명, () => {})

두번째 파라미터는 생략 해도되지만 이 함수를 넣어 줌으로써 코드를 보았을때 이액션 생성 함수의 파라미터로 어떤 값이 필요한지 쉽게 파악 할수 있다.

  • handleActions : 리듀서 작성
const reducer = handleActions({
  [액션타입명]: (state,action)=>({...state, input:action.payload})
  //...
},초기state값)

export default reducer

payload 이름을 새로 설정해 주면 action.payload가 정확히 어떤 값을 의미하는지 쉽게 파악 할수 있다.

const reducer = handleActions({
 [액션타입명]: (state,{payload:input})=>({...state, input})
//...
},초기state값)

export default reducer

적용하기

2. Hooks 이용하여 컨테이너 컴포넌트 만들기

useSelector

useSelector HOOK을 사용하면 connect함수를 사용하지 않고도 리덕스의 상태를 조회 할수 있다.

const 결과 = useSelector(상태_선택_함수)
  • 상태_선택_함수 : mapStateToProps 와 형태가 똑같다

useDispatch

const dispatch = useDispatch();
dispatch({type:'SAMPLE_ACTION});

useDispatch를 사용할 때는 useCallback과 함게 사용하는 것을 습관화 하자( 최적화 할수 있다)

useStore

const store = useStore();
store.dispatch({type:'SAMPLE_ACTION'});
store.getState();

컴포넌트 내부에서 리덕스 스토어 객체를 직접 사용할수 있다. 하지만 정말 어쩌다가 스토어에 직접 접근해야하는 상황에만 사용해야 한다. 이를 사용하는 때는 흔치 않을 것이다.

useActions 유틸 hook 만들어서 사용하기

공식 문서에서 그대로 복사하여 사용할수 있다.

이 훅을 사용하면, 여러 개의 액션을 사용해야 하는 경우 코드를 훨씬 깔끔하게 정리하여 작성할 수 있다.

src/lib/useActions

import { bindActionCreators } from 'redux';
import { useDispatch } from 'react-redux';
import { useMemo } from 'react';

const useActions = (actions, deps) => {
  const dispatch = useDispatch();
  return useMemo(
    () => {
      if (Array.isArray(actions)) {
        return actions.map((a) => bindActionCreators(a, dispatch));
      }
      return bindActionCreators(actions, dispatch);
    },
    deps ? [dispatch, ...deps] : [dispatch],
  );
};

export default useActions;

useActions는 두 가지 파라미터가 필요하다.

첫번째 : 액션 생성 함수로 이루어진 배열
두번째: deps배열( 이안에 들어있는 원소가 바뀌면 액션을 디스패치하는 함수를 새로 만든다.)

connect함수를 사용하면 해당 컨테이너 컴포넌트의 부모 컴포넌트가 리렌더링될 때 해당 컨테이너 컴포넌트의 props가 바뀌지 않는다면 리렌더링이 자동으로 방지되어 성능이 최적화 된다.
하지만 useSelector를 사용하면 최적화 작업이 자동으로 이루어 지지 않는다 . 하지만 최적화를 위해서 React.memo(컴포넌트명) 을 사용하면 해결할수 있다.

profile
어제보다는 오늘 더 나은

0개의 댓글