0. 디렉터리 생성

1. action types 수정
//src/actions/ActionTypes.js
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const SET_COLOR = 'SET_COLOR';
export const CREATE = 'CREATE';
export const REMOVE ='REMOVE';
2. action creators 수정
//src/actions/index.js
import * as types from './ActionTypes';
export const increment = (index) => ({
type:types.INCREMENT,
index
});
export const decrement = (index) => ({
type:types.DECREMENT,
index
});
export const setColor = (color, index) => ({
type:types.SET_COLOR,
color,
index
});
export const create = (color) => ({
type:types.CREATE,
color
});
export const remove = () => ({
type:types.REMOVE
});
3. reducers 수정
//src/reducers/index.js
import * as types from '../actions/ActionTypes';
const initialState = { counters: [{ color: 'black', number: 1 }] };
const reducers = (state = initialState, action) => {
const {counters} = state;
switch (action.type) {
case types.CREATE:
return {
counters:[...counters,{color:action.color, number:1}]
};
case types.REMOVE:
return {
counters:counters.slice(0,counters.length-1)
};
case types.INCREMENT:
return {
counters:[...counters.slice(0,action.index),
{
...counters[action.index],
number:counters[action.index].number+1
},
...counters.slice(action.index+1, counters.length)
]
};
case types.DECREMENT:
return {
counters:[...counters.slice(0,action.index),
{
...counters[action.index],
number:counters[action.index].number-1
},
...counters.slice(action.index+1, counters.length)
]
};
case types.SET_COLOR:
return {
counters:[...counters.slice(0,action.index),
{
...counters[action.index],
color:action.color
},
...counters.slice(action.index+1, counters.length)
]
};
default:
return state;
}
}
export default reducers;
4. Button 컴포넌트 생성
//src/components/Button.js
import React from 'react';
import PropTypes from 'prop-types';
import './Button.css';
const Button = ({onCreate, onRemove}) => {
return (
<div className="Button">
<div className="btn add" onClick={onCreate}>CREATE</div>
<div className="btn rm" onClick={onRemove}>REMOVE</div>
</div>
);
};
Button.propTpes = {
onCreate:PropTypes.func,
onRemove:PropTypes.func
};
Button.defaultProps = {
onCreate: () => console.warn("onCreate is not defined")
}
export default Button;
/* src/components/Button.css */
.Button {
display:flex;
}
.Button .btn{
flex:1;
display:flex;
align-items: center;
justify-content: center;
height: 3rem;
color: white;
font-size: 1rem;
cursor: pointer;
}
.Button .add{
background: green;
}
.Button .add:hover{
background: yellow;
}
.Button .rm{
background: red;
}
.Button .rm:hover{
background: yellow;
}
5. CounterList 컴포넌트 생성
//src/components/CounterList.js
import React from 'react';
import Counter from './Counter';
import PropTypes from 'prop-types';
const CounterList = ({ counters, onIncrement, onDecrement, onSetColor }) => {
const counterList = counters.map((counter, i) => (
<Counter
key={i}
index={i}
{...counter}
onIncrement={onIncrement}
onDecrement={onDecrement}
onSetColor={onSetColor}
/>
));
return (
<div className="counterList">
{counterList}
</div>
);
};
CounterList.propTypes = {
onIncrement: PropTypes.func,
onDecrement: PropTypes.func,
onSetColor: PropTypes.func
};
Counter.defaultProps = {
counters:[],
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 CounterList;
6. Counter 컴포넌트 수정
//src/components/Counter.js
import React from 'react';
import PropTypes from 'prop-types';
import './Counter.css';
const Counter = ({ number, color, index, onIncrement, onDecrement, onSetColor }) => {
return (
<div
className="counter"
onClick={()=>onIncrement(index)}
onContextMenu={(e) => { //마우스 오른쪽 버튼을 눌렀을 때 메뉴가 열리는 이벤트
e.preventDefault(); //메뉴가 열리는 것을 방지
onDecrement(index); // => 마우스 오른쪽 클릭 : 감소
}}
onDoubleClick={()=>onSetColor(index)}
style={{ backgroundColor: color }}
>
{number}
</div>
);
};
//{ number, color, onIncrement, onDecrement, onSetColor
Counter.propTypes = {
index: PropTypes.number,
number: PropTypes.number,
color: PropTypes.string,
onIncrement: PropTypes.func,
onDecrement: PropTypes.func,
onSetColor: PropTypes.func
};
Counter.defaultProps = {
index:0,
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;
7. getRandomColor 라이브러리 생성
// src/lib/getRandomColor.js
const getRandomColor = () => {
const colors = ['green', 'yellow', 'blue'];
const random = Math.floor(Math.random() * 3);
return colors[random];
};
export default getRandomColor;
8. CounterContainer 삭제, CounterListContainer 생성
// src/containers/CounterListContainer.js
import CounterList from '../components/CounterList';
import * as actions from '../actions';
import {connect} from 'react-redux';
import getRandomColor from '../lib/getRandomColor';
const mapStateToProps = (state) => ({
counters:state.counters
});
const mapDispatchToProps = (dispatch) => ({
onIncrement:(index)=>dispatch(actions.increment(index)),
onDecrement:(index)=>dispatch(actions.decrement(index)),
onSetColor:(index) => {
const color = getRandomColor();
dispatch(actions.setColor(color, index));
}
});
const CounterListContainer = connect(mapStateToProps, mapDispatchToProps)(CounterList);
export default CounterListContainer;
9. App 컨테이너 컴포넌트 수정
// src/containers/App.js
import React, {Component} from 'react';
import CounterListContainer from './CounterListContainer';
import Button from '../components/Button';
import {connect} from 'react-redux';
import * as actions from '../actions';
import getRandomColor from '../lib/getRandomColor';
class App extends Component {
render() {
const {onCreate, onRemove} = this.props;
return (
<div className="App">
<Button
onCreate={onCreate}
onRemove={onRemove}
/>
<CounterListContainer />
</div>
);
}
};
const mapDispatchToProps = (dispatch) => ({
onCreate: ()=>dispatch(actions.create(getRandomColor())),
onRemove:()=>dispatch(actions.remove())
});
export default connect(null,mapDispatchToProps)(App);
- AppContainer 안에서 App과 redux를 connect하지 않고 App 컴포넌트에서 바로 연결
- store.state값을 필요로 하지 않으므로 connect()의 ampStateToProps는 null로 설정
'Javascript > projects' 카테고리의 다른 글
blog 1-1 (0) | 2019.09.05 |
---|---|
Todo-list (5) : redux 적용 (0) | 2019.09.01 |
Counter (1) : 카운터 만들기 (0) | 2019.08.29 |
Todo-list (4) : 리렌더링 최적화 하기 (0) | 2019.08.29 |
Todo-list (3) : 데이터 추가, 수정, 삭제 (0) | 2019.08.29 |