[Redux] redux 기본 개념

김효식 (HS KIM)·2020년 8월 17일
0

wecode

목록 보기
31/35
post-custom-banner

redux를 사용하는 이유는 뭘까? redux를 사용하는 이유는 컴포넌트 간에 state값이 이동해야 하는 경우에, depth가 깊어지는 것을 방지하고 state값을 전역에서 관리할 수 있기 때문이다.


생활코딩의 react-redux 강의를 보고 개념 공부를 해서 위는 생활코딩의 예제다.
Add Number Root안의 Add Numberbutton을 누르면 Display Number Root안의 Display Numberinput값이 변경되어야 한다.
아직까지는, depth가 그렇게까지 깊지는 않지만 위의 상황이 수십 수백번 반복된다고 생각하면 redux의 필요성을 충분히 느끼게 될 것이다.

npm install --save react-redux
npm install --save-dev redux-devtools

이제 redux를 사용하기 위해 install 해준다.

import { createStore } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";

export default createStore(function (state, action) {
  if (state === undefined) {
    return { number: 0 };
  }
  if (action.type === "INCREMENT") {
    return { ...state, number: state.number + action.size };
  }
  return state;
}, composeWithDevTools());

store.js 파일을 src아래에 만들고, 위와같이 createStore를 해준다. createStore의 인자로 들어가는 함수는 reducer라고 불리는데, 간단하게 state의 값을 관리해주는 곳이라고 생각하면 된다. reducerstatecomponentstate는 조금은 다른 개념인데, 처음에 reduxstate가 값이 없기 때문에 초기값을 지정해주거나, 위와같이 값이 undefined인 경우에 조건문을 걸어줘야 한다. 그 뒤로는 전달받은 action의 type에 따라 조건을 걸어주고,Spread Operator로 기존의 state값을 복사해주고 바뀌는 값만 변경해준다. 지정되지 않은 action.type이 들어올 때는 바로 statereturn해주면 된다.
composeWithDevTools는 필수 기능은 아니지만, 아래와 같이 웹브라우저에서 확장프로그램 사용을 위해 필요하다.

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";
import "./index.css";

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root"),
);

원래는 redux를 사용해야 하는 모든 파일에서 storeimport해야 하지만, 위처럼 Provider를 사용하여 전체를 감싸주면 최상위 컴포넌트에서 store를 한번만 import해주면 된다.

import AddNumber from "../components/AddNumber";
import { connect } from "react-redux";

function mapDispatchToProps(dispatch) {
  return {
    onClick: (size) => {
      dispatch({ type: "INCREMENT", size: size });
    },
  };
}

export default connect(null, mapDispatchToProps)(AddNumber);

AddNumber.js 파일에는 값을 변경시키는 버튼이 있는데, 버튼을 작동시켜서 store의 변경된 값을 반영시키기 위해서는 원래 해당 함수subscribe해줘야 한다. 그런데 react에서는 connect를 사용하여 그런 작업을 할 필요 없게 해준다. 그리고 컴포넌트를 재활용하기 위해서 아래 AddNumber와 같이 두개의 파일로 분리해서 container에서는 값을 component쪽으로 전달해주기만 하는데, connect를 사용하면 위와 같은 분리 작업을 편리하게 만들어 준다.

AddNumber.js (container)

import AddNumber from "../components/AddNumber";
import { connect } from "react-redux";

function mapDispatchToProps(dispatch) {
  return {
    onClick: (size) => {
      dispatch({ type: "INCREMENT", size: size });
    },
  };
}

export default connect(null, mapDispatchToProps)(AddNumber);

connect의 첫번째 인자로는 변하게 할 state의 값이 들어가고, 두번째로는 변하게하는 함수가 들어간다.
mapDispatchToPropsreduxdispatchreact의 컴포넌트의 props로 연결시키는 정보를 담고 있는 함수다.

AddNumber.js (component)

import React, { Component } from "react";

export default class AddNumber extends Component {
  state = { size: 1 };
  render() {
    return (
      <div>
        <h1>Add Number</h1>
        <input
          type="button"
          value="+"
          onClick={() => {
            this.props.onClick(this.state.size);
          }}
        ></input>
        <input
          type="text"
          value={this.state.size}
          onChange={(e) => {
            this.setState({ size: Number(e.target.value) });
          }}
        ></input>
      </div>
    );
  }
}

Updated Information
위와 같이 파일을 2개로 만들 필요없이 하나의 파일에서 connect를 사용해도 된다. 하나의 파일에서도 props를 사용하는데 그 때 사용되는 propsstore에서 받아온 state를 지칭한다.(connect를 사용하면 component를 감싸고 있는 wrapper가 있다고 생각하면 된다)

DisplayNumber (Container)

import DisplayNumber from "../components/DisplayNumber";
import { connect } from "react-redux";

function mapReduxStateToReactProps(state) {
  return {
    number: state.number,
  };
}

export default connect(mapReduxStateToReactProps)(DisplayNumber);

DisplayNumberRootstate의 값을 직접 변경하지 않기 때문에 두번째 인자의 값은 넣지 않는다.
mapReduxStateToReactPropsreduxstorestatereactpropsmapping시켜주는 정보를 담고 있는 함수다.

DisplayNumber (Component)

import React, { Component } from "react";

export default class DisplayNumber extends Component {
  render() {
    return (
      <div>
        <h1>Display Number</h1>
        <input type="text" value={this.props.number} readOnly></input> {this.props.unit}
      </div>
    );
  }
}
profile
자기개발 :)
post-custom-banner

0개의 댓글