본문 바로가기
퍼블리셔일기

redux란? nextjs에서 redux 시작하기, 사용법

by 지짱히메 2022. 7. 31.
반응형

redux란?

중앙데이터 저장소 라고 보면 될듯.

 

컴포넌트나눠서 부모자식간에 일일이 계속 전달하고 그런게 귀찮으니까

한꺼번에 중앙에서 관리하는거.

그래서 컴포넌트가 필요로 할때 부분적으로 가져다 쓰거나 전체적으로 가져다가 쓸 수 있게.

 

중앙 데이터 저장소 (유사: Mobx(초보가아니거나 생산성 위하면 괜춘) 나 contextapi(앱이 작을때 가볍게) 등등)


redux 장점

원리가 간단, 확실하고 에러가 날일이 별로 없고 에러가 나도  추적이 가능함 = 앱이 안정적이어짐\

 

redux 단점

but,  코드량이 많아짐


왜? 사람들은 redux를 택하나?

 

중앙저장소는 서버에서 데이터를 받아옴.

서버에서 데이터를 받아오는 것은 항상 비동기임. 이말은 즉슨, 서버에서 데이터 요청할때마다 

100% 성공의 확률로 주지 않음. 

> 따라서 비동기방식으로 주기 때문에 항상 실패를 대비해야 한다. [요청, 성공,실패] 3단계로 구분됨.

[비동기 요청이 많음 > contextapi 사용 > 어라? redux, mobx랑 비슷하네.. > 그럴바엔 그냥 라이브러리 쓰는거임]

&

화면을 비즈지스로직이랑 분리(데이터 가져오는 로직이랑 분리) 컴포넌트는 그냥 화면 그리는 용으로.

 

 


Redux를 이해하자.

 

redux란 reduce에서 이름을 따온것임~

 

reduce 뜻 : 줄이다.

 

ㅇㅋ??

 

 ex>

 

{

name:'jihye',

age:27,

password : 'babo'

}

 

라는 중앙 데이터 저장소를 만들었음.

그러면 ~ 각 컴포넌트에서 필요로 할 때 꺼내서 쓸 수가 있음.

 

그런데 데이터 조회뿐만 아니라(가져가는거)  수정, 추가, 삭제도 가능함!!

 

Redux에서는 데이터를 바꾸려면 action 이라는 걸 꼭 필수로 만들어 줘야함.

 

 action 예를들어

{

type: 'CHANGE_NICKNAME',

data: 'jihyechang'

}

 

그리고 이 액션을 중앙저장소에  dispatch(보내다) 를 하면  데이터가 바뀝니다.

 

위의 경우는 name부분이 기존 jihye에서 jihyechang 으로 바뀌게 되겠져?

그러면 name을 가져다 쓴 컴포넌트 모든 부분이 jihye에서 jihyechang으로 바끼게되는고~


자, 여기서 reducer라는 개념이 필요한데

action을 dispatch 한다고 해서 알아서 저장소에서 jihye 를 jihyechang으로 바꿔주는게 아님 ~~~

wow~

자바스크립트는 type: 'CHANGE_NICKNAME',

이게 먼지 모르거든..

 

그래서 우리가 어떻게 뭘 바꿔야되는지 일일이 적어줘야한다는 말씀.

 

그걸 reducer에서 ^^

 

보통 switch로 쓴다.

 

switch(action.type){
  case 'CHANGE_NICKNAME': //타입명
    return{ // 새롭게 {} 를 만들어야 히스토리가 남기때문
    	...state,  //참조를 위해서 아예 바꿔버리면 내역-히스토리 가 남지않는다.
        name: action.data,
	}
    case 'CHANGE_AGE':
    return{
    	...state,
        age: action.data,
	}
}

 

이런식으로

 

이게... 그냥..  redux의 끝이다.

 

데이터를 바꾸고 싶을 때마다 액션을 만들어 줘야하고, 액션을 어떻게 처리해야 할지 직접 적어줘야하고(reducer만들어줘야하고).

그래서 코드량이 매우 많아진다.

 

하지만 데이터 내역들이 다 추적이 되어서 좋음.

 

redux dev tool 쓰면 데이터 돌려감기 등 타임머신 기능 할 수 있어서 좋음

데이터 변화하는 게 모두 내역으로 남아있기 때문에.

일일이 로그인 했다 안했다 난리 안부려도댐

테스트하기에 좋다.

 

배포모드일때는 개발모드와 달리 히스토리를 버려서 메모리 문제 없음.

 

 


 

 

Redux 사용

 

1. npm init

2. npm i react react-dom next

3. npm i -D nodemon webpack

4. npm i -D eslint >.eslintrc

5. npm i -g next

6. npm i next-redux-wrapper >store폴더 > configureStore.js

import { createWrapper } from "next-redux-wrapper";
import { applyMiddleware, createStore, compose } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import rootReducer from "../reducers";
 
const configureStore = () => {
  const middlewares = [];
  const enhancer =
    process.env.NODE_ENV === "production"
      ? compose(applyMiddleware(...middlewares)) // 배포용 히스토리안쌓이게
      : composeWithDevTools(applyMiddleware(...middlewares)); //히스토리 쌓이게
      const store = createStore(rootReducer, enhancer);
      return store;
};

const wrapper = createWrapper(configureStore, {
  debug: process.env.NODE_ENV === "development",
});
export default wrappe
 
7. _app.js에서 

임포트 하고 익스포트

 

export default wrapper.withRedux(프로젝트명);

 

 

8. npm i redux

프로바이더로 안감싸도됨 next에서는

 

9. npm i react-redux

 

 

(그냥 스터디인데 쓰는 문법 참고만)

10. reducers 폴더 생성, index.js생성 (리듀서가 길어져서 combineReducers 써서 나눈상태) 

 

import { HYDRATE } from "next-redux-wrapper";
import { combineReducers } from "redux";
import user from "./user";
import post from "./post";

//이전상태, 액션 => 다음상태
const rootReducer = combineReducers({
  index: (state = {}, action) => {//서버쪽에서도 돌아갈 수 있도록 ssr
    switch (action.type) {
      case HYDRATE:
        console.log("HYDRATE", action);
        return { ...state, ...action.payload }; 
      default:
        return state;
    }
  },
  user,
  post,
});

export default rootReducer;
 
 
user.js
 
export const initialState = {
  isLoggedIn: false,
  user: null,
  signUpData: {},
  loginData: {},
};

export const loginAction = (data) => {
  return {
    type: "LOG_IN",
    data,
  };
};

export const logoutAction = () => {
  return {
    type: "LOG_OUT",
  };
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case "LOG_IN":
      return {
        ...state,
        isLoggedIn: true,
        user: action.data,
      };
    case "LOG_OUT":
      return {
        ...state,
        isLoggedIn: false,
        user: null,
      };
    default:
      return state;
  }
};
export default reducer;
이런식으로 씀.
 
 
dispatch 예시
 
 
프로필
const UserProfile = () => {
  const dispatch = useDispatch();
  const onLogOut(로그아웃버튼함수) = useCallback(() => {
    dispatch(logoutAction());
  }, []);
 
 
로그인폼
const LoginForm = () => {
  const dispatch = useDispatch();
 
 
앱레이아웃
const AppLayout = ({ children }) => {
  const isLoggedIn = useSelector((state) => state.user.isLoggedIn);
반응형