퍼블리셔일기

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

지짱히메 2022. 7. 31. 17:08
반응형

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);
반응형