React Hooks Redux 와 ContextAPI 비교

Taesol Kwon·2020년 5월 14일
0

Wecode

목록 보기
31/32

Redux 와 ContextAPI 비교

Redux : 전역상태를 생성하고 관리하기 위한 라이브러리(타 프레임워크에서 사용가능) + 그 외에 여러 기능 제공

<구성>

  • Store : 전역 상태 보관소
  • Reducer : Store에 접근시킴
  • Action : Reducer에 Action을 지시
  • Subscription : Store에 보관된 상태를 가져옴
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

import { createStore } from 'redux';
import { Provider } from 'react-redux';

const store = createStore(/*your root reducer*/);

ReactDOM.render(
  <Provider store={store}>
  	<App />
  </Provider>,
  document.getElementById('root')
);
// App.js
export default function App() {
	return (
      <Player>
      	<ItemBox />
      </Player>
    )
}

Action

// src/Redux/Actions/index.js
export const addMusic = (song) =>{
    return {
        type: "ADD_MUSIC",
        payload: song
    }
}

Reducer

// src/Redux/Reducers/songList.js
export default function songList(state = initialState, action) {
  switch (action.type) {
        case "ADD_MUSIC":
            return [...state, ...action.payload]
        default:
            return state;
  }
};
// src/Redux/rootReducers.js
import { combineReducers } from "redux";
import songList from "Redux/Reducers/songList";

const rootReducer = combineReducers({
    songList,
});

export default rootReducer;

Subscription

// src/Components/ListBox.js
import { connect } from 'react-redux';
import { addMusic } from '../Redux/Actions';

const mapStateToProps = (state) => {
  return {
    songList: state.songList,
  };
};

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    addMusic: (song) => {
      dispatch(addMusic(song));
    },
  };
};

// mapStateToProps가 없으면 null 써주면 된다.
export default connect(mapStateToProps, { addMusic })(ListBox);
// export default connect(mapStateToProps, mapDispatchToProps)(ListBox);

ContextAPI : 상태의 중앙 관리를 위한 상태 관리 도구. React에서만 사용 가능하고 Redux와 다르게 여러 저장소가 존재할 수 있다.

<구성>

  • Context : 전역 상태 보관소
  • Provider : 전역 상태를 제공
  • Consumer : 전역 상태를 받아 사용

Hooks를 이용한 ContextAPI

// index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import { StateProvider } from "./Store/store";

ReactDOM.render(
  <React.StrictMode>
    <StateProvider>
      <App />
    </StateProvider>
  </React.StrictMode>,
  document.getElementById("root")
);

Store = Context

  • useContext : context 객체(React.createContext에서 반환된 값)을 받아 그 context의 현재 값을 반환한다.
  • useReducer : current state 와 action 두 개의 인자를 받고 new state를 반환한다.(Reduce와 같은 역할을 한다)
// src/Store/store.js
import React, { createContext, useContext, useReducer } from "react";

const initialState = { count: 0};
const countContext = createContext(initialState);
const useCount = () => useContext(countContext);
const { Provider } = countContext;

const StateProvider = ({ children }) => {
  const [state, dispatch] = useReducer((state, action) => {
    switch (action.type) {
      case "ADD_NUM":
        return { count: state.count + action.payload}
      default:
        throw new Error();
    }
  }, initialState);

  return <Provider value={[state, dispatch]}>{children}</Provider>;
};

export { StateProvider, useCount };
// App.js
import React from "react";
import "./App.css";
import Button from "./components/Button";
import { useCount } from "./Store/store";

const App = props => {
  const [state] = useCount();

  return (
    <>
      <div>{state.count}</div>
      <Button></Button>
    </>
  );
};

export default App;
// AddCount 컴포넌트는 Button 컴포넌트의 자식 컴포넌트이다.
// src/components/AddCount
import React from "react";
import { useCount } from "../Store/store";

const AddCount = props => {
  const [store, dispatch] = useCount();
  
  const handleClick = () => {
    dispatch({
      type: "ADD_NUM",
      payload: 1
    });
  };

  return (
    <div>
      <button onClick={handleClick}>더하기 + 1</button>
    </div>
  );
};

export default AddCount;

Reducer는 왜 순수함수여야 할까?

순수 함수

  • 기본적으로 입력 데이터를 변경하지 않고 외부 상태 (데이터베이스, DOM 또는 전역 변수와 같은)에 의존하지 않으며 동일한 입력값에 대해 동일한 출력값을 일관되게 제공하는 함수를 “순수(pure)” 함수라고 한다.
const add = (a, b) => a + b; //pure function

why?

Redux는 state가 불변해야 한다는 특징을 가지고 있다. 불변한다는 것은 state가 변경되면 안된다는 뜻이 아니라 state가 수정되면 안된다는 뜻이다.
state 값을 변경할때는 스프레드 연산자로 기존 state 값을 복사한 뒤 변경된 state를 반환한다. Redux는 reducer를 거친 state가 변경됐는지를 검사하기 위해 state 객체의 주소를 비교하는데 state의 복제본을 만들어 반환하면 이전의 state와 다른 주소값을 가르키기 때문에 state가 변경되었다고 판단한다. 반대로 state를 복제하는 것이 아닌 속성만 수정하여 반환하면 기존의 state 객체와 가리키는 주소값이 같이 때문에 변경감지가 되지 않는다.
그렇다면 왜 주소를 비교하는 걸까? 그 이유는 객체 속성을 비교하는 것은 깊은 비교라고 하는데 복잡하고 무거운 알고리즘이 필요하기 때문이다.

profile
사진촬영을 좋아하는 프론트엔드 개발자입니다.

0개의 댓글