TIL 22-05-04 (2)

thisisyjin·2022년 5월 4일
0

TIL 📝

목록 보기
40/113

React.js

Today I Learned ... react.js

🙋‍♂️ Reference Book

🙋‍ My Dev Blog


리액트를 다루는 기술 DAY 18

  • Redux Middleware

Redux 미들웨어

  • 리덕스 미들웨어를 통한 비동기 작업 관리.

API 서버를 연동할 때는 API 요청에 대한 state도 잘 관리해야 한다.

  • 요청 성공시 서버에서 받아온 response에 대한 state를 관리하고,
  • 요청 실패시 서버에서 반환한 error에 대한 state를 관리해야 함.

프로젝트 환경 설정

1) 패키지 설치

$ yarn add redux react-redux redux-actions

2) counter 모듈 작성

modules/counter.js

import { createAction, handleActions } from 'redux-actions';

const INCREASE = 'counter/INCREASE';
const DECREASE = 'counter/DECREASE';

export const increase = createAction(INCREASE);
export const decrease = createAction(DECREASE);

const initialState = 0;

const counter = handleActions(
    {
        [INCREASE]: state => state + 1,
        [DECREASE]: state => state - 1
    },
    initialState
);

export default counter;

3) rootReducer 생성

modules/index.js

import { combineReducers } from 'redux';
import counter from './counter';

const rootReducer = combineReducers({
    counter
});

export default rootReducer;

리듀서 함수가 한개지만, combineReducers를 해주었다.
-> 여러개가 아닐 때도 rootReducer로 export 해주기위해 combineReducers({})를 해주자.

4) index.js (스토어 생성, Provider)

redux의 createStore()로 스토어 생성 후,
react-redux의 Provider 컴포넌트의 props로 store을 넘겨줌.

src/index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css'
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './modules';

const store = createStore(rootReducer);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

5) Counter, CounterContainer 생성

components/Counter.js

const Counter = ({ onIncrease, onDecrease, number}) => {
    return (
        <div>
            <h1>{number}</h1>
            <button onClick={onIncrease}>+1</button>
            <button onClick={onDecrease}>-1</button>
        </div>
    )
}

export default Counter;

containers/CounterContainer.js

import { connect } from "react-redux";
import { increase, decrease } from "../modules/counter";
import Counter from "../components/Counter";

const CounterContainer = ({ number, increase, decrease }) => {
    return (
        <Counter number={number} onIncrease={increase} onDecrease={decrease} />
    );
};

export default connect(
    state => ({
        number: state.counter
    }),
    {
        increase,
        decrease
    }
)(CounterContainer);

+) useSelector, useDispatch 사용 ver.

import { increase, decrease } from "../modules/counter";
import Counter from "../components/Counter";
import { useSelector, useDispatch } from "react-redux";

const CounterContainer = () => {
    const number = useSelector(state => state.counter);
    const dispatch = useDispatch();

    return (
        <Counter number={number}
            onIncrease={() => dispatch(increase)}
            onDecrease={() => dispatch(decrease)}
        />
    );
};

export default CounterContainer;

6) App 렌더링

import CounterContainer from "./containers/CounterContainer";

function App() {
  return (
    <div>
      <CounterContainer/>
    </div>
  );
}

export default App;

미들웨어 (middleware)

리액트 미들웨어는 액션을 디스패치 했을 때 리듀서에서 처리하기에 앞서, 사전에 지정된 작업을 실행한다.
= 액션과 리듀서의 중간자 역할.

미들웨어 생성

  • 사실 프로젝트 작업시 직접 생성하기보다는 다른 미들웨어를 가져와서 사용하면 됨.
  • 미들웨어의 작동원리를 알아보기 위해 직접 만들어보자.

lib/loggerMiddleware.js

const loggerMiddleware = store => next => action => {
    // 기본 구조
};

export default loggerMiddleware;

loggerMiddleware은 3중 중첩함수로 구성되어 있다.
(화살표 함수를 연달아서 사용하였음.)

const loggerMiddleware = function loggerMiddleware(store) {
    return function (next) {
        return function (action) {

        };
    };
};
  • 미들웨어는 함수를 반환하는 함수를 반환하는 함수임.
  • store은 리덕스 스토어 객체를,
    action은 디스패치된 액션을 가리킴.
  • next는 함수형태로, dispatch()와 비슷한 역할을 함.
    -> next(action) 호출시 그 다음 처리해야 할 미들웨어에게 액션을 넘겨주고
    그 다음 미들웨어가 없다면 리듀서에게 액션을 넘겨줌.

미들웨어 구현

const loggerMiddleWare = store => next => action => {
    console.group(action && action.type); 	// 액션 타입으로 log를 그룹화
    console.log('이전 상태', store.getState());
    console.log('action', action);
    next(action); 	// 다음 미들웨어(or 리듀서)에게 전달
    console.log('다음 상태', store.getState());   // 업데이트된 state
    console.groupEnd();	 // 그룹화 끝
}

export default loggerMiddleWare;

스토어에 적용

  • 리덕스 미들웨어를 스토어에 적용함.
  • 스토어를 생성하는 과정에서 적용하면 됨.
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css'
import { applyMiddleware, createStore } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './modules';
import loggerMiddleWare from './lib/loggerMiddleware';

const store = createStore(rootReducer, applyMiddleware(loggerMiddleWare));

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

-> redux 라이브러리의 applyMiddleware 함수의 인자로 미들웨어를 넣어줌.

createStore() 함수

createStore(루트리듀서, applyMiddleware(미들웨어));

console창 결과

  • action.type을 기준으로 그룹화 되어 나타난다.
    이전 상태와 다음 상태, 그리고 action 객체를 알 수 있다.

console.group()

  • mdn 문서 참조
  • console.groupEnd()가 나올 때 까지 들여쓰기 되어서 콘솔에 출력됨.
profile
기억은 한계가 있지만, 기록은 한계가 없다.

0개의 댓글