Next.js에서 Redux사용하기 (Redux wrapper) (1/2)

Joey Hong·2020년 7월 24일
5

Redux

목록 보기
1/1

중앙데이타저장소 Store

  • 컴포넌트에서 공통적으로 쓰이는 데이타가 흩어져있기 때문에 부모 컴포넌트에서 데이타를 받아서 자식 컴포넌트에게 각각 보내줘야한다
  • 컴포넌트끼리 데이타를 전달하는 과정도 매우 복잡하고 오류가 발생하기도 쉽다.
  • 규모가 있는 서비스라면 중앙데이타저장소 Store를 최소 한 개 만들어 중앙에서 모든 데이타를 관리하고 보내주는 것이 편하다
  • 중앙데이타저장소는 Redux, React의 contextedAPI, Mobax, Apolo 등이 있다

Redux

  • Redux는 원리가 간단하고 모든 수정사항을 기록한다.
  • 모든 히스토리가 기록되어 에러 추적이 쉽고 안정적이다.
  • 하지만 코드량이 많아진다.
  • 중앙은 앱이 커지면 데이타를 쪼개는 작업이 필요한데 Redux는 reducer들을 쪼개는 기능을 제공해주어 편리하다 (reducer란 전달받은 action에 따라 상태를 어떻게 업데이트할지 정의해주는 함수)
  • 사용법이 쉬워 초보자에게 추천되지만 전체적으로 가장 많이 사용되는 라이브러리기도 하다

Mobax

  • Mobax는 코드량이 매우 적어 생산성을 높일 수 있다
  • 하지만 실수를 했을 때 추적이 어렵다
  • 초보를 벗어나면 생산성을 위해 추천되는 라이브러리지만 Redux보다는 사용률이 낮다

Context API

  • 앱 규모가 작을 때 권장된다
  • 큰 규모의 프로젝트는 차라리 리덕스나 모백스를 사용하는 것이 낫다
    • 중앙데이타저장소는 서버에서 데이타를 받아오는데 이 과정은 비동기다
    • 서버가 고장나거나 네트워크 에러가 생기면 데이타가 안 올수 있다
    • 실패에 대비하기위해 요청, 성공, 실패 3단계를 직접 구현해야한다.
    • 3단계 구현 코드를 컴포넌트마다 넣어줘야해 의도치 않은 코드 중복이 발생
    • 위의 코드만 밖으로 따로 빼낼 수 있지만 비동기 요청이 많으면 context API도 리덕스와 모백스와 비슷해진다
    • 따라서 리덕스나 모백스 등이 알아서 처리해주는 것이 편하다
	useEffect(() => {
    	axios.get('/data')
      		.then(() => {
        		setState(data);
        })
      		.catch(() => {
        		setError(error);
        })
    })

Redux && redux-wrapper

설치

  • 넥스트가 설치되어있는 front 디렉토리에서 리덕스 설치
    npm i redux

  • Redux의 손쉬운 사용을 위해 redux-wrapper 설치 (Redux와 사용법이 약간 다르다)
    npm i next-redux-wrapper

  • front/store/configureStore.js 파일 생성

      import { createWrapper } from 'next-redux-wrapper';
      import {createStore} from 'redux';

      const configureSotre = () => {
        const store = createStore(reducer);
        return store;
      };

      const wrapper = createWrapper(configureSotre, {
        debug: process.env.NODE_ENV === 'development,'
      });

      export default wrapper;
  • _app.js 파일 수정
    • wrapper 불러오기
    • wrapper를 사용해서 내보내기
    • Nodebird는 앱 이름
	import wrapper from '../store/configureStore.js`
	.
	.
    	.
    	export default wrapper.withRedux(Nodebird);
	//wrapper로 감싸줘야 프로젝트의 모든 컴포넌트와 페이지에 적용된다
  • 예전에는 _app.js의 return 내부를 Provider로 감싸야했는데 지금은 redux가 알아서 감싸주니 비워두어야한다 (사용자가 감싸면 중복되어 에러 발생)
	//before
	return (
            <Provider store={store}>
            </Provider>
    	);


	//from redux@6
	return (
            <>
            </>
    	);

Redux의 원리

진행 과정

  1. 앱의 상태를 객체 형식으로 작성한다 state (좌)
  2. 변경하고 싶은 내용을 action으로 만든다 (우)
    • action의 이름을 적는 type
    • 변경사항을 적는 data
  3. actiondispatch한다
  4. dispatchactionreducer에 따라 처리한다 (아래)
    • reduceraction 어떻게 처리할지 정의해준다
    • 예를 들어 switch를 값을 변경해주는 것이다
    • caseactiontype을 적어준다
    • 바꾸고싶은 값에 action.data를 넣어준다
  • 중앙관리저장소에 앱의 전체 상태를 하나의 객체로 표현한다

{
  name: 'zerocho',
  age: '27',
  password: 'babo'
}
  • action을 생성해서 무엇으로 변경할지 적어준다

    • 변경사항마다 action을 만들어줘야한다
  {
    type: 'CHANGE_NICKNAME' // action이름
    data: 'boogicho' // 변경될 데이타값
  }
  {
    type: 'CHANGE_AGE'
    data: 30,
  }
  • action을 dispatch하면 reducer에 따라 중앙저장소의 데이타가 변경된다

  • reducer에 데이타를 어떻게 변경해야하는지 정의해준다

  switch (action.type) {
    case 'CHANGE_NICKNAME':	//action의 type
      return {			//새로운 객체를 리턴
        ...state,			//유지할 state들은 그대로 사용
        name: action.data,		//변경할 state를 action.data로 바꿔준다
      }
    case 'CHANGE_AGE':		//또 다른 action 처리를 정의
      return {
        ...state,
        age: action.data,
      }
  }
  • 중앙저장소의 데이타가 reducer가 정의한대로 변경되면 해당 데이타를 갖다 쓰는 컴포넌트의 모든 데이타가 변경된다

    • 지정한 데이타만 변경된 채로 새로운 객체가 만들어지고 그 객체를 가져다 쓰는 방식이다

장단점

  • 변경할 때마다 action과 reducer를 하나씩 추가해줘야해서 코드량이 많아진다
  • action 하나하나가 Redux에 기록이 되어 그 내역을 보고 버그를 찾기가 매우 쉽다
  • 개발 변경사항을 거꾸로 거슬러 올라가며 개발사항을 테스트하기 쉽다

새로운 객체를 만드는 이유

  • reducer에서는 매번 일부만 수정된 새로운 객체를 반환한다.
    return { //새로운 객체 반환
      ...state,
      name: action.data,
    }

JavaScript에서 참조한 두 객체는 같은데 Redux는 매번 새로운 객체를 만들기 때문에 서로 다른 객체이다

{} === {} //false


const a = {};
const b = a;
a === b //true
  • 이렇게 새로운 객체를 만들면 변경 전과 후를 모두 기록할 수 있다
    //새로운 객체 만들기
    const prev = { name: 'zerocho' }
    const next = { name: 'boogicho' }


    ---
    //기존 객체 참조
    const next = prev;
    next.name = 'bbogicho';

    prev.name; // boogicho

객체 내의 바뀌지않는 데이타는 예전 것 참조

    return {
      ...state, // 바뀌지않는 부분은 예전 것 참조
      name: action.data,
    }
  • 일일히 입력하며 작업량이 많아지는 것을 방지
  • 메모리 관리를 위해
    • action하나를 실행할 때마다 새로운 객체가 생기기 때문에 메모리가 많이 필요하다
    • 바뀌는 데이타만 새로 만들고 유지하는 데이타는 참조하는 방식으로 진행
    const next = { b: 'c' };
    const prev = { a: next };
    const next = { ...prev};

    prev.a === next.a //true
    prev === next //false
  • 유지되는 데이타 a는 예전 것을 참조했기에 같은 객체로 본다
profile
개발기록

0개의 댓글