출처는 공식 문서입니다.
https://ko.redux.js.org/
Redux는 React 대신에 state를 관리해주는 라이브러리이다.
컴포넌트가 많아지고 깊어졌을 때 불편한 점을 해결하기 위해 사용한다.
redux는 react 컴포넌트 외부에서 자유롭게 움직이는 컨테이너라고 생각해야 한다.
actoin, reducer 등의 redux의 개념을 컴포넌트에서 사용하기 위해선 props로 받아와야 한다.
props라는 것을 부모 컴포넌트의 state 값을 받아올 때 사용하는 것처럼
redux의 state를 props로 받아온다고 생각하자.
redux는 컴포넌트와 부모자식 사이가 아니라 하늘에 떠 다니는? 그런 존재라고 생각해야한다.
redux는 다음과 같이 작동한다.
Action Creator > Action > dispatch > Reducer > State
이를 이해하기 위해선 react와 redux를 쓴 react의 렌더링 과정의 차이를 아는게 도움이 된다.
React 렌더링 과정.
- component 내에 이벤트 호출(클릭, 입력 등)
- 이벤트와 연결 된 setState 또는 useState 호출
- state 값 변화
- 렌더링
Redux를 사용한 React의 렌더링 과정
- component 내에 이벤트 호출(클릭, 입력 등)
- 이벤트와 연결된 action creator 호출
- action creator가 생성한 action 호출
- action이 reducer로 전달(dispatch)
- dispatch된 action의 영향으로 reducer의 state값이 변화
- 렌더링
state 값의 변화로 렌더링이 일어난다는 점은 똑같다.
state의 변화가 컴포넌트 내부에서 일어나는지, redux의 store에서 일어나는지의 차이다.
redux는 state의 값을 컴포넌트 외부에서 대신 관리해주는 대행사라고 생각하면 될 것 같다.
음...부모님(부모컴포넌트)한테서 용돈(state)을 내가(자식 컴포넌트) 직접 받는(props) 것이 아니라
부모님(컴포넌트)이 용돈(state)을, 은행계좌를(redux store) 통해 전달하고(dispatch) 내가(컴포넌트) 이후에 받는다(props)?
이게 더 이해하기 어렵나.. 부모컴포넌트>자식컴포넌트가 아니라 컴포넌트>리덕스>컴포넌트로 state 값을 주고 받는다.
import React from "react"; import ReactDOM from "react-dom"; import { Provider } from "react-redux";
// redux 라이브러리에서 createStore를 가져온다. import { createStore } from "redux";
import App from "./components/App"; //createStore의 인자로 사용할 reducer를 가져온다. import reducers from "./reducers";
ReactDOM.render( // Provider 태그 안에 app의 store을 만들고 reducer를 넣는다. <Provider store={createStore(reducers)}> <App /> </Provider>, document.querySelector("#root") );
store.. reducer.. 헷갈린다.
redux의 store에 reducer의 내용을 채우는것인가!
store를 만들고 나면 이제 똑같은 말 아닌가!
//action creator 선언 export const selectNumber = () => { return { //action 선언 type: "SELECTED_NUMBER", //액션은 대문자와 스네이크 표기법을 사용. payload: 1, //액션이 전달하는 내용 } }
1. import React from "react"; import { connect } from "react-redux";
2. // 액션생성자 가져오기(index.js 파일이라 이렇게 작성해도 된다.) import { selectNumber } from "../actions";
3. class 예시컴포넌트 extends Component { render(){ return( <div> //props로 액션생성자(selectNumber)을 받아옴 //클릭시, 액션이 dispatch되어 reducer로 감 <button onClick={()=> this.props.selcectNumber()}> select </button> </div> ) } }
4. //mapStateToProps가 없어서 connect()의 첫번째 인자를 null로 처리 //connect()의 두번째 인자로 액션생성자(selectNumber)를 전달 export default connect(null, { selectNumber })(예시컴포넌트)
컴포넌트에서 액션을 사용하려면
공식 홈페이지의 번역은 위와 같은데 솔직히 이게 무슨 말이진 진짜 이해 안된다.
컴포넌트에서의 이벤트(클릭, 입력)를 통해 액션은 store로 전달(dispatch)가 되며
이후 store에 있는 state값을 변화시키는 것으로 보아...
action(creator) + dispatch를 useState 또는 setState의 개념으로 보아도 될 것 같다.
1 //redux에서 combineReducers를 가져온다. import { combineReducers } from 'redux'
2 //reducer 선언1(만들기) const numbersReducer = () => { return [ {number: 0}, {number: 1}, {number: 2}, {number: 3}, ] }
3 //reducer 선언2(액션에 영향을 받는 리듀서) //reducer(previousState, action)의 형태 //최초의 state 값은 없고 action을 받는다. const selectNumberReducer = (selectNumber = null, action) => { if(action.type === 'SELECTED_NUMBER){ return action.payload } return selectNumber }
4 //combineReducers로 reducer들 합치기 export default combineReducers({ numbers: numbersReducer, //numbers라는 키의 값으로 numbersReducer 할당 selectNumber: selectNumberReducer, //selectNumber라는 키의 값으로 selectNumberReducer 할당 })
combineReducers사용(1번과 4번)
Reducer 사용(2번과 3번)
import React from "react"; import ReactDOM from "react-dom"; import { Provider } from "react-redux"; import { createStore } from "redux"; import App from "./components/App";
// reducers를 가져온다.(이는 combineReducers 이다.) // 즉 모든 reducer들의 집합이다. import reducers from "./reducers";
ReactDOM.render( //가져온 리듀서를 createStore의 인자로 넣는다. //connect()가 된 모든 컴포넌트에서 reducer에 접근할 수 있다. <Provider store={createStore(reducers)}> <App /> </Provider>, document.querySelector("#root") );
reducer 함수는 액션을 받아 상태를 반환하는 순수함수이다.
이와 관련된 API 호출이나 라우팅과의 연계. 그리고
기존의 state(previousState)의 값이 배열이나 객체의 형태일때의 변화 등의 내용은 다루지 않았다.