과제를 수행하면서 작성한 코드에 대한 내 설명을 작성해 본다.
내가 쓴 코드를 리뷰 하는것이기 때문에, 남이 봤을때는 순서와 정리가 매끄럽지 못할 수 있다ㅠㅠ
리뷰 순서
src/index.js
src/App.js
src/View/Main/MainContainer.js
src/hocs/withView.js
src/store/view.js
& src/store/reducers.js
& src/store/createStore.js
src/View/Main/MainView.js
src/components/Calender/Calender.js
src/components/HourSelector/HourSelector.js
다음과 같은 순서로 코드를 리뷰하겠다.
src/index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import store from "./store/createStore";
ReactDOM.render(
<React.StrictMode>
<App store={store} />
</React.StrictMode>,
document.getElementById("root")
);
<App/>
에 props
로 createStore 에서 생성된 store
를 넣어준다.
어떻게 만들어졌는지는 5번에서 추가설명이 될것이다.
src/App.js
import React from "react";
import "./app.scss";
import { Provider } from "react-redux";
import Main from "./View/Main/index";
const App = ({ store }) => {
return (
<Provider store={store}>
{/* Provider 를 이용해 store를 사용할 수 있게 한다. */}
<Main />
</Provider>
);
};
export default App;
App 함수에 props로 들어온 store 를 선언하고 <Provider>
로 App.js
에서 렌더될 Route 를 추가해준다.
src/View/Main/MainContainer.js
import withView from "../../hocs/withView";
import { compose } from "recompose";
import MainView from "./MainView";
// compose 를 이용하여 MainView 에 withView 를 넘겨준다.
const wrappedComponent = compose(withView([{ key: "date" }]))(MainView);
export default wrappedComponent;
recompose 라는 library 가 사용되었다.
recompose 는 hOC(higher Order Component) 를 더 유용하게 사용할 수 있게 만들어진 라이브러리 이다.
위 코드에서 살펴보면 withview
에서 return 한 값을 mainView
에 넘겨주겠다는 의미이다.
이제 withView
에서 어떤 내용을 MainView
에 넘겨주는지 살펴보자.
src/hocs/withView.js
import React from "react";
import { connect } from "react-redux";
import { receiveView } from "../store/view";
export default (option = []) => (ComposedComponent) => {
// * 1. 배열이 있다면 해당 배열이 들어오고, 없다면 빈 배열 정의.
// * 2. ComposedComponent 는 MainView가 될것임.
class withView extends React.Component {
render() {
// * 7. props로 받아온 것(state, dispatch)들을 ComposedComponent 로 넣어준 다음 다시 return 함.
return <ComposedComponent {...this.props} />;
}
}
const mapStateToProps = (state) => {
// * 3. store에 있는 state
// * 4. option 으로 들어온 key 를 이용해 store의 state에 있는 값에 접근함.
const result = {};
option.forEach((item) => {
result[item.key] = state.view[item.key];
});
return result;
};
const mapDispatchToProps = (dispatch) => ({
// * 5. 액션함수를 가져옴.
viewAction: {
receiveView: (key, state) => dispatch(receiveView(key, state)),
// dispatch 실행되면 해당 reducer 함수 실행
},
});
// * 6. state 와 dispatch 를 props로 withView 로 넘겨준다.
return connect(mapStateToProps, mapDispatchToProps)(withView);
};
export default (option = []) => (ComposedComponent) => {};
이부분을 보면 option = []
은 옵션이 들어온다. 옵션이 없다면 기본값으로 빈 배열을 가지게 할것이다.
MainContainer
에서 withView([{key: 'date' }])
로 option
이 쓰인다.
그리고 composedComponent
는 MainContainer
에서
compose(withView([{key: 'date'}]))(MainView)
맨마지막에 MainView
가 된다.
3번
redux state(store) 에 있는 값을 props 로 준다는 의미인 함수 mapStateToProps
에서 사용된 코드를 보면
const result = {};
option.forEach((item) => {
result[item.key] = state.view[item.key];
});
return result;
(즉, key: 'date')
을 forEach
각각의 배열에 어떤 처리를 할것인가 보면,result
라는 객체에 key : value
형태로 만들겠다는 것이다.key
로는 option
으로 들어온 key
(즉, date) 는 redux store
의 item.key
(즉, date)로 선언하겠다.result
에 저장된 내용을 return 함.4번,5번
dispatch를 props 로 주는 함수를 보면
const mapDispatchToProps = (dispatch) => ({
viewAction: {
receiveView: (key, state) => dispatch(receiveView(key, state)),
// dispatch 실행되면 해당 reducer 함수 실행
},
});
return connect(mapStateToProps, mapDispatchToProps)(withView);
};
viewAction
이라는 key 로 receiveView 에 (key, state) 를 인자로 넣어주게 되면 receiveView (액션함수)가 실행된다.
액션함수가 실행되면 reducer 가 실행되어 역할수행.
6번
그리고 connect
에서 withView
에 값을 넘겨준다.
7번
withView class 에서 props 로 받아온 것들을 ComposeComponent
에 넣어준다.
class withView extends React.Component {
render() {
// * 7. props로 받아온 것(state, dispatch)들을 ComposedComponent 로 넣어준 다음 다시 return 함.
return <ComposedComponent {...this.props} />;
}
}
이렇게 withView (hOC)를 이용해서 값을 넘겨준다.
src/store/view.js
& src/store/reducers.js
& src/store/createStore.js
src/store/view.js
export const RECEIVE_VIEW = "RECEIVEW_VIEW";
export const receiveView = (key, state = null) => {
return {
key,
type: RECEIVE_VIEW,
payload: state,
};
};
const initialState = {};
export default function viewReducer(state = initialState, action) {
if (action.type === RECEIVE_VIEW) {
return Object.assign({}, state, { [action.key]: action.payload });
} else {
return state;
}
}
액션 선언과 액션함수, 리듀서함수를 같은 파일에 작성했다.
액션 함수 receiveView
는 key
와 state
가 들어간다. (state가 없을 경우는 null)
액션함수가 실행되면 viewReducer 가 실행되는데, store 에 key
와 action의 payload 즉 (위에서 설정한 state
)가 store에 들어간다.
src/store/reducer.js
import { combineReducers } from "redux";
import viewReducer from "./view";
export default combineReducers({
view: viewReducer,
});
reducer 는 하나의 함수로만 존재해야 하기 때문에 여러개의 reducer 함수를 하나로 모아놓은 combineReducer 가 필요하다. combineReducer에 view 에서 만든 viewReducer 를 추가한다.
src/store/createStore.js
import { createStore } from "redux";
import reducers from "./reducers";
import { composeWithDevTools } from "redux-devtools-extension";
const store = createStore(reducers, composeWithDevTools());
export default store;
이제 store 를 만들어야 한다.
createStore 로 만들고, 안에는 위 파일 (store/reducer.js) 에서 만든 combineReducer 가 들어간다. 그리고 chrome devtool extension (추가설치한 library) 를 넣어줘서 확인할 수 있게 한다.
여기서 만들어진 createStore를 src/index.js
에서 import 한다.
이 이후는 MainView
에 대한 내용이므로 다음포스트에서 진행.