0. 디렉터리 생성

1. App.js 생성
//src/containers/App.js
import React, {Component} from 'react';
class App extends Component {
render() {
return (
<div>
Counter
</div>
);
}
}
export default App;
2. index.js 생성
//src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './containers/App';
ReactDOM.render(<App />, document.getElementById('root'));
3. Counter 컴포넌트 생성
//src/components/Counter.js
//presentational component
// view를 담당, 리덕스 스토어에 직접 접근할 권한은 없으며 오직 props로만 데이터를 가져올 수 있음, 주로 함수형 컴포넌트로 작성
import React from 'react';
import PropTypes from 'prop-types';
import './Counter.css';
const Counter = ({ number, color, onIncrement, onDecrement, onSetColor }) => {
return (
<div
className="counter"
onClick={onIncrement}
onContextMenu={(e) => { //마우스 오른쪽 버튼을 눌렀을 때 메뉴가 열리는 이벤트
e.preventDefault(); //메뉴가 열리는 것을 방지
onDecrement(); // => 마우스 오른쪽 클릭 : 감소
}}
onDoubleClick={onSetColor}
style={{ backgroundColor: color }}
>
{number}
</div>
);
};
//{ number, color, onIncrement, onDecrement, onSetColor
Counter.propTypes = {
number: PropTypes.number,
color: PropTypes.string,
onIncrement: PropTypes.func,
onDecrement: PropTypes.func,
onSetColor: PropTypes.func
};
Counter.defaultProps = {
number: 0,
color: 'black',
onIncrement: () => console.warn('onIncrement function is not defined'),
onDecrement: () => console.warn('onDecrement function is not defined'),
onSetColor: () => console.warn('onSetColor function is not defined')
}
export default Counter;
onContextMenu() : 마우스 오른쪽 버튼을 눌렀을때 메뉴가 열리는 이벤트
e.preventDefault() : 메뉴가 열리는 것을 방지
/*src/components/Counter.css*/
.counter {
width: 10rem;
height: 10rem;
border-radius: 100%;
display: flex;
align-items: center;
justify-content: center;
margin: 1rem;
color: white;
font-size: 3rem;
cursor: pointer;
user-select: none; /* 더블클릭을 통한 텍스트 선택 불가능 */
transition: background-color 0.2s;
}
App.js에 Counter.js 렌더링
//src/containers/App.js
import React, {Component} from 'react';
import Counter from '../components/Counter';
class App extends Component {
render() {
return (
<div>
<Counter />
</div>
);
}
}
export default App;
4. action types 생성
//src/actions/ActionTypes.js
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const SET_COLOR = 'SET_COLOR';
5. action creator function 생성
//src/actoins/index.js
import * as types from './ActionTypes';
export const increment = () => ({
type:types.INCREMENT
});
export const decrement = () => ({
type:types.DECREMENT
});
export const setColor = (color) => ({
type:types.SET_COLOR,
color:color
});
6. reducer 생성
//src/reducers/reducerColor.js
import * as types from '../actions/ActionTypes';
const initialState = {
color: 'red'
};
const reducerColor = (state = initialState.color, action) => {
switch (action.type) {
case types.SET_COLOR:
return { color: action.color };
default:
return state;
}
}
export default reducerColor;
//src/reducers/reducerNumber.js
import * as types from '../actions/ActionTypes';
const initialState = {
number:1
}
const reducerNumber = (state=initialState, action) =>{
switch (action.type) {
case types.INCREMENT:
return {number:state.number+1};
case types.DECREMENT:
return {number:state.number-1};
default:
return state;
}
};
export default reducerNumber;
//src/reducers/index.js
import reducerNumber from './reducerNumber';
import reducerColor from './reducerColor';
import {combineReducers} from 'redux';
//리듀서에 의해 만들어진 state는 어플리케이션 state와 합쳐지고
const reducers = combineReducers({
numberData : reducerNumber,
colorData : reducerColor
});
//새로 만들어진 state는 컨테이너로 전달
export default reducers;
7. 스토어 생성
//src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './containers/App';
//creating store
import { createStore } from 'redux';
import reducers from './reducers';
const store = createStore(reducers, window.devToolsExtension && window.devToolsExtension());
ReactDOM.render(<App />,ndocument.getElementById('root'));
- 리엑트에서 스토어를 생성할 때는 보통 프로젝트의 엔트리 포인트인 src/index.js파일에서 만든다
8. Provider 컴포넌트로 App.js와 store 연동
//src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './containers/App';
//creating store
import { createStore } from 'redux';
import reducers from './reducers';
const store = createStore(reducers, window.devToolsExtension && window.devToolsExtension());
//react와 store 연동
import { Provider } from 'react-redux';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
- Provider는 react-redux 라이브러리에 내장된 리액트 app에 store를 연동시키는 컴포넌트
9. CounterContainer 컴포넌트 생성
//src/containers/CounterContainer.js
import Counter from '../components/Counter';
import * as actions from '../actions';
import {connect} from 'react-redux'; // subscrie
//랜덤하게 색깔 선택
export const getRandomColor = () => {
const colors = ['green', 'yellow', 'blue'];
const random = Math.floor(Math.random()*3);
return colors[random];
};
const mapStateToProps = (state) => ({
number:state.numberData.number,
color:state.colorData.color
});
const mapDispatchToProps = (dispatch) => ({
onIncrement: ()=>dispatch(actions.increment()),
onDecrement: ()=>dispatch(actions.decrement()),
onSetColor:() => {
const color = getRandomColor();
dispatch(actions.setColor(color));
}
});
//Promte Counter from a component to a container
// => it needs to know about dispatch methods, which would be available as props
const CounterContainer = connect(mapStateToProps, mapDispatchToProps)(Counter);
export default CounterContainer;
- 리덕스의 buit-in-function인 subscribe 대신 react-redux 라이브러리의 connect(mapStateToProps, mapDispatchToProps, mergeProps) 메서드를 사용하여 컴포넌트를 스토어에 연결
- mapStateToProps : state값을 파라미터로 받아 props로 전달하는 함수, props로 사용할 객체를 반환
- mapDispatchToProps : 액션을 스토어에게 전달하는 dispatch함수를 파라미터로 받고 props에 연결하는 함수. 전달하는 함수들을 객체 안에 넣어서 반환
- mergeProps : state와 dispatch가 동시에 필요한 함수를 props에 전달할 때 사용
//src/containers.App.js
import React, {Component} from 'react';
import CounterContainer from './CounterContainer';
class App extends Component {
render() {
return (
<div>
<CounterContainer />
</div>
);
}
}
export default App;
'Javascript > projects' 카테고리의 다른 글
Todo-list (5) : redux 적용 (0) | 2019.09.01 |
---|---|
Counter (2) : 멀티 카운터 (0) | 2019.08.29 |
Todo-list (4) : 리렌더링 최적화 하기 (0) | 2019.08.29 |
Todo-list (3) : 데이터 추가, 수정, 삭제 (0) | 2019.08.29 |
Todo-list (2) : UI 디자인 및 구성 (0) | 2019.08.29 |