npm install redux react-redux
📂 src/actions
📂 src/reducers
📂 src/store
📂src/reducers
📂src/store
폴더 안에 index.js
파일을 만들기
📂src/store/index.js
에서 store를 create 해준다
store 폴더를 만들지 말고 그냥 src/index.js에서 createStore해도 무방하다
// src/store/index.js
import { createStore } from "redux";
import rootReducer from "../reducers/index";
const store = createStore(rootReducer);
export default store;
App.js의 부모 컴포넌트로 Root.js를 따로 만들어서 사용했기 때문에
src폴더 바로 하위의 index.js가 이렇다 (App 대신 Root를 render하는 형태)
// src/index.js
ReactDOM.render(
<Root />,
document.getElementById('root')
);
아래와 같이 Root.js 파일에 react-redux Provider 를 Import 하여 감싸주었고 store를 전송하여 리액트에서 액션이 처리되었을 때 이벤트를 받아서 하위에 있는 다른 컴포넌트가 다시 렌더링 될 수 있도록 도와준다.
// src/client/Root.js
import React from "react";
import App from '../App';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from '../store';
const Root = () => (
<BrowserRouter>
<Provider store={store}>
<App/>
</Provider>
</BrowserRouter>
);
export default Root;
=> Root.js를 따로 만들지 않았다면 그냥 src/index.js에서 App을 Provider로 감싸주면 된다
모든 action type을 하나의 파일에 담아서 import해서 사용하는 방법으로 하였다. (근데 그냥 해당 action파일에서 바로 지정해서 쓰는게 편리할 듯 하다.)
📂 src/actions
에 ActionTypes.js
라는 파일을 만들었다. 여기에 action type들을 지정해 줄 것이다.
이제 이 type으로 어떠한 reducer랑 연결될지 알 수 있다.
❗ 예시로 ADD_USERINFO라는 회원정보를 store에 저장하는 action을 만들어 보자 ❗
먼저 ActionTypes.js 에 type을 선언해준다
// src/actions/ActionTypes.js
export const ADD_USERINFO = "ADD_USERINFO";
📂 src/actions
에 예시로 src/actions/user.js
를 만들겠다.
import { ADD_USERINFO } from "./ActionTypes";
export const addUserInfo = userInfo => ({
type: ADD_USERINFO,
payload: userInfo
});
rootReducer를 정의하고 세부 reducer를 정의하여
rootReducer에서 세부 reducer들을 combineReducers로 묶어준다
📂 src/reducers
에 예시로 src/reducers/user.js
를 만들겠다
src/reducers/index.js에 모듈화 처리를 해줘야한다
=> 쪼갠 파일(user.js)을 import하여 combineReducers
로 묶어준다
앞으로 쪼갤 reducer 파일들을 combineReducers에 넣어주면 된다
import { combineReducers } from "redux";
import user from "./user"
const rootReducer = combineReducers({
user : user,
})
export default rootReducer;
이제 state값을 변화시킬 reducer를 작성해 보자
action에서 payload로 받은 userInfo (data)를 userState의 userInfo에 저장해 줄 것이다!
이때 reducer는 불변성을 유지
하여아 하기 때문에 Spread 문법을 사용하였다.(혹은 concat, filter등 사용)
import * as type from "../actions/ActionTypes";
const userState = {
userInfo: {},
};
const user = (state = userState, action = {}) => {
switch (action.type) {
case type.ADD_USERINFO:
return {
...state,
userInfo: { ...action.data }
}
default:
return state;
}
};
export default user;
action을 사용하는데에는 dispatch
와 connect
두 가지 방법이 있다.
import store from '../store';
2) import { useSelector } from 'react-redux';
1) const userInfo = store.getState().user.userInfo;
2) const userInfo = useSelector( state => state.user.userInfo);
store.dispatch({ type: ADD_USERINFO, data: userInfo });
type에 원하는 action type을 적고, data에 같이 전달할 payload를 보내주면 된다
state는
getState()
혹은useSelector 훅
을 사용하여 접근할 수 있다
const mapStateToProps = (state) => {
return {
userInfo: state.user.userInfo,
}
}
const mapDispatchToProps = (dispatch) => {
return {
addUserInfo: (userInfo) => dispatch({type:ADD_USERINFO, data: userInfo}),
}
}
...
const TestComponent = () => {
...
}
// connect의 첫번째자리는 mapState, 두번째 자리는 mapDispatch (자리 위치 지켜줘야함)
// 마지막엔 연결할 컴포넌트 이름
export default connect(mapStateToProps, mapDispatchToProps)(TestComponent);
mapDispatchToProps로 dispatch를 할 수 있는데 이제 addUserInfo
로 선언했으므로
컴포넌트 내에서 함수처럼 편하게 호출 가능하다!
ex)
const userInfo = { name : '아무개', age: 30 }
addUserInfo(userInfo)
mapStateToProps도 userInfo
로 state의 userInfo 값을 선언했으므로 컴포넌트 내에서 자유롭게 userInfo로 접근 가능!