Code States TIL - Redux

최동혁·2021년 2월 22일
0

기존의 React에서는 부모 컴포넌트의 state를 자식 컴포넌트에서 접근하려면 부모 컴포넌트에서 함수를 만들고 이 함수를 자식에게 props로 전달해주어야했습니다. 그런데 자식의 자식의 자식의... 자식 컴포넌트에게 이 함수를 전달해주려면 이 사이의 모든 컴포넌트가 함수를 전달해주어야 했습니다. 이를 방지하기 위해 전역 state를 사용한 것이 Redux입니다.

공식문서를 보면 "Redux는 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너입니다."라고 합니다. 즉 React가 아니어도 사용가능합니다.
그림으로 Redux의 작동방식을 살펴보면

와 같은 식입니다.

store는 state를 보관합니다. store를 만드는 방법은 reducer를 인자로 createStore를 호출합니다. 두번째 인자로 초기 상태를 지정해줄 수 있습니다.

import {createStore} from 'redux'
let store=createStore(reducer);

(reducer는 직접 만들어야합니다)
store.getState()로 현재 store의 상태를 볼 수 있고, let unsubscribe=store.subscribe(func);로 dispatch마다 func이 실행되게 할 수 있습니다. store.subscribe(func)의 결과물은 함수로 이 함수가 실행되면(unsubscribe()) dispatch마다 func이 실행되는 것이 멈춥니다.
이 store를 모든 컴포넌트에서 접근 가능하게 하려면

import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
const store=createStore(reducer);
ReactDOM.render(
  <Provider store={store}>
    <Aaa/>
  </Provider>,
  document.getElementById('root')
);

와 같은 식으로 Provider를 이용해 쓸 수 있습니다. Provider의 저장소는 모든 자식 컴포넌트에서 사용가능합니다.

React에서는 이 state들로 UI를 만듭니다. UI에는 버튼 같은 것들이 있을 수 있고 이런 입력들은 Action을 통해 새로운 명령을 내립니다.

Action은 type이라는 property를 갖는 객체입니다. 그 외의 property를 추가할 수도 있습니다. 액션 생산자로 비슷한 액션들을 만들어낼 수도 있습니다.

const action={
  type: "EAT"
  food: "meat"
}
const eat=function(food){
  return {
    type:"EAT",
    food:food
  };
}

Dispatcher는 액션을 store로 보내 reducer가 state를 바꿀 수 있게 합니다.

dispatch(action);

공식문서에서는 createStore(reducer)로 만든 store객체의 dispatch property를 가져오는 식으로 되어있습니다. (const dispatch=store.dispatch) react hook으로는 cosnt dispatch=useDispatch(); 같은 식으로 씁니다.
dispatch의 인자는 action이 아니라 함수가 올 수도 있습니다. 이 때는 함수를 실행합니다. 보통 비동기적으로 action을 적용시키는 경우 dispatch(action)을 포함한 함수를 인자로 줍니다.

Reducer는 state와 Action을 인자로 갖고 다음 state를 되돌려주는 함수입니다.

function reducer(state,action){
  if(action.type==='EAT'){
    return Object.assign({},state,{
      meal:action.food
    });
  }
  return state;
}

와 같은 식으로 빈 객체에 state를 복사한 후 meal을 변경합니다.
여러 reducer들을 하나로 합칠 수도 있습니다.

import {combineReducers} from 'redux'
const reducer=combineReducers({
  reducer1,
  reducer2
});

또 mapStateToProps, mapDispatchToProps라는 함수를 만들어서 이것들을 컴포넌트와 connect해주어야합니다. 이것으로 state가 변경될 때 props가 변경되거나 onClick으로dispatch를 props에 따라 다르게 사용하거나 할 수 있습니다.
mapStateToProps는 state와 props를 인자로 받아 props를 추가/변경하고 mapDispatchToProps는 dispatch를 props에 추가/변경해줍니다.

const mapStateToProps=(state,props)=>{
  return{
    eating:state.meal
  }
}
const mapDispatchToProps=(dispatch,props)=>{
  return{
    onClick:()=>dispatch(eat(props.food))
  };
}
const ConnectedAaa=connect(
  mapStateToProps,
  mapDispatchToProps
)(Aaa);//Aaa라는 React Component를 구현했다고 합시다

요약
1. Action의 타입과 Action 생성자를 만듭니다.
2. Action에 따라 state를 return하는 reducer들을 만들고 combineReducers로 묶습니다.
3. 묶은 reducer로 createStore를 호출해 store를 만들고 Provider로 모든 컴포넌트에서 쓸 수 있게 만듭니다.
4. connect로 state,dispatch와 React Component를 묶습니다.

그런데 과제로 나온 방식에는 useSelector, useDispatch라는 게 있습니다.
React hook Component의 함수 안에서 useSelector로 state를 가져오고 useDispatch로 dispatch를 가져오네요.

function Aaa(props){
  const state=useSelector(state=>state.aaa);
  const {meal}=state;
  const dispatch=useDispatch();
  
  const handleClick=(food)=>{
    dispatch(eat(food));
  }
  
  return (
    <div onClick={handleClick(props.food)}>
      {props.food}
    </div>
  );
}

와 같은 식인 것 같습니다. 이건 react hooks가 추가된 이후의 문법이라고 합니다.

0개의 댓글