Redux

준호·2020년 8월 25일
0
Redux Mobx contextAPI 특징

redux : 원리가 간단해서 에러가 덜 남 , 코드량이 많아짐

mobx : 코드량이 적어짐, 에러 추적이 힘듬

contextAPI : 주로 컴포넌트에 코드가 직접 들어가서 보기 좋지 않음 ,쓰다보면 어차피 redux처럼 쓰게 됨

Store, Action, Dispatch, Reducer, Store

State : 데이터 저장소

Action : State를 변경하기 위한 명령

dispatch : Action을 실행 해주는 것

Reducer : Action을 사용해서 State를 어떻게 바꿀지 정함 switch문을 사용

Store : reducerstate를 합침? ( 나중에 다시 알아보기 )

Reducer ...state 를 써줘야 하는 이유

reducer에서 state.name같이 직접적으로 변경을 시도하면 참조 관계가 유지되어 History가 남지 않는다.

Next에 Redux를 붙이는 방법

npm i redux next-redux-wrapper

reduxnextredux를 붙이기 위한 next-redux-wrapper를 설치한다.

	// ./store/configureStore.js
import { createStore } from 'redux';
import createWrapper from 'next-redux-wrapper'
import reducer  from '../reducer';

const configureStore = () => {
  const store = createStore(reduce)
    return store;
}

const Wrapper = createWrapper(configureStore, {
  debug: process.env.NODE_ENV == 'development'
})

export default Wrapper;

configureStore.js 세팅을 해준다

// ./pages/_app.js
export default Wrapper.withRedux(App);

공용파일 _app.js 의 컴포넌트를 HOC로 감싸준다

React에서는 react-redux에 포함된 Provider로 이렇게 감싸준다
하지만 Next에서는 알아서 감싸주기 때문에 따로 써주지 않는다.

Redux DevTools 세팅하기

npm i redux-devtools-extension
	// ./store/configureStore.js
(...) 
 
import { createStore, applyMiddleware, compose } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension'

const configureStore = () => {
  const middlewares = []
  const enhancer = process.env.NODE_ENV === 'production'
    ? compose(applyMiddleware(...middlewares)) // 배포용
    : composeWithDevTools(applyMiddleware(...middlewares)) // 개발용
  const store = createStore(reducer, enhancer)
  return store;
}

(...)

Reducer 구조

// ./reducer/index.js

const initialState = {
  user: {
    isLoggedIn: false,
    user: null,
    signUpData: {},
    loginData: {},
  },
  post: {
    mainPosts: [],
  }
} // State의 초기값

const LOG_IN = 'LOG_IN';  // ACTION명 이름 재정의

export const LogInAction = data => {
  return {
    type: LOG_IN,
    data
  }
} // 넘겨줄 Action
// 컴포넌트에서 dispatch(LoginAction(data로 넘겨줄값) 으로 사용)

const RootReducer = (state = initialState, action) => {
  switch(action.type) {
    case LOG_IN : 
    return { 
      // LOG_IN ACTION이 감지되면  아래의 행동을 취한다.
     ...state,
      user: {
        ...state.user, 
        // 객체의 불변성을 유지하며 안의 값만 바꾸기 위함
        isLoggedIn: true,
        user: action.data
      }
    }
    default :
      // default 는 꼭 필요, 없으면 에러남
    return {
      ...state
    }
  }
}
LoginForm에서 LoginAction을 쓰려면?
// ./component/LoginForm.js
(...)
import { useDispatch } from 'react-redux';
import { LogInAction } from '../reducer'
(...)
 const LoginForm = () => {
  const dispatch = useDispatch()
  
  const onSubmitLogin = useCallback(() => {
    dispatch(LogInAction(id, password))
  }, [id, password])
  
  return (
    <FormWrap onFinish={onSubmitLogin}>
  (...)
   </FormWrap>
  )
  
(...)
}
AppLayout에서 isLoggedIn State가 필요하다면?
// ./component/AppLayout.js
(...)
import { useSelector } from 'react-redux';
const AppLayout = ({ children }) => {
  const isLoggedIn = useSelector(state => state.user.isLoggedIn)
  (...)
   {isLoggedIn ? <UserProfile/> : <LoginForm/>}
   (...)
}

reducer의 파일을 분리하는 방법

// ./reducer/user.js

// index에서 user에 해당하는 부분을 모두 가져옴
export const initialState = {
  isLoggedIn: false,
  user: null,
  signUpData: {},
  loginData: {},
} 

const LOG_IN = 'LOG_IN';
const LOG_OUT = 'LOG_OUT';

export const LogInAction = data => {
  return {
    type: LOG_IN,
    data
  }
}

export const LogOutAction = () => {
  return {
    type: LOG_OUT
  }
}

const UserReducer = (state = initialState, action) =>{
  switch(action.type) {
    case LOG_IN : 
    return {
      ...state, 
      isLoggedIn: true,
      user: action.data
    } // state의 구조가 바뀌었으니 이곳도 바뀜
    case LOG_OUT : 
    return {
      ...state,
      isLoggedIn: false,
      user: null
    }
    default: 
    return state;
  }
}

export default UserReducer;

// 이하 post폴더도 이와 같은 방식으로 세팅
// ./reducer/index.js
import { combineReducers } from 'redux'
import UserReducer from './user';
import PostReducer from './post';

const RootReducer = combineReducers({
  //combineReducers로 묶어두고 객체 안에 묶을 컴포넌트들을 넣으면 된다.
  UserReducer,
  PostReducer
})

export default RootReducer;

reducer 구조가 바뀌었으니 Action을 사용하는 컴포넌트의 링크도 바꿔주자

import { LogInAction } from '../reducer/user'
profile
빠르게 발전중인 프론트엔드 개발자

0개의 댓글