Skip to content

Commit 7179105

Browse files
committed
9-1 에러수정
1 parent bc4a430 commit 7179105

12 files changed

+215
-38
lines changed

chapter9/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"dependencies": {
66
"react": "^16.8.6",
77
"react-dom": "^16.8.6",
8-
"react-scripts": "3.0.0"
8+
"react-scripts": "3.0.0",
9+
"redux": "^4.0.1"
910
},
1011
"scripts": {
1112
"start": "react-scripts start",

chapter9/src/AddColorForm.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ class AddColorForm extends Component {
99
}
1010

1111
submit(e) {
12-
const {_title, _color} = this.refs;
1312
e.preventDefault();
13+
const {_title, _color} = this;
1414
this.props.store.dispatch(addColor(_title.value, _color.value));
1515
_title.value = '';
1616
_color.value = '';
@@ -20,8 +20,8 @@ class AddColorForm extends Component {
2020
render() {
2121
return (
2222
<form onSubmit={this.submit}>
23-
<input ref={input => _title = input} type="text" placeholder="색 이름" required />
24-
<input ref={input => _color = input} type="color" required/>
23+
<input ref={input => this._title = input} type="text" placeholder="색 이름" required />
24+
<input ref={input => this._color = input} type="color" required/>
2525
<button>추가</button>
2626
</form>
2727
);

chapter9/src/App.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ import {v4} from 'uuid'
33
import AddColorForm from './AddColorForm';
44
import StarRating from './StarRating';
55
import PropTypes from 'prop-types';
6+
import SortMenu from './sortMenu';
67
import Color from './Color';
78
import { rateColor, removeColor } from './actions';
8-
import {sortFunction} from 'lib/array-helpers';
9-
9+
import { sortFunction } from './lib/array-helpers';
1010

1111

1212
const ColorList = ({store}) => {
1313
const {colors, sort} = store.getState();
1414
const sortedColors = [...colors].sort(sortFunction(sort));
15-
<div className="color-list">
15+
return (<div className="color-list">
1616
{(colors.length === 0) ?
1717
<p>색이 없습니다. 색을 추가해주세요</p> :
1818
sortedColors.map(color =>
@@ -22,7 +22,7 @@ const ColorList = ({store}) => {
2222
onRemove={()=> store.dispatch(removeColor(color.id)) }/>
2323
)
2424
}
25-
</div>
25+
</div>)
2626
}
2727

2828

@@ -32,13 +32,15 @@ class App extends Component {
3232
this.state = {
3333
colors : []
3434
}
35+
3536
this.addColor = this.addColor.bind(this);
3637
this.rateColor = this.rateColor.bind(this);
3738
this.removeColor = this.removeColor.bind(this);
3839
}
3940
render() {
4041
const { addColor, rateColor, removeColor } = this;
4142
const { colors } = this.state;
43+
const store = this.props.store;
4244
return (
4345
<div className="app">
4446
<SortMenu store={store}/>

chapter9/src/Star.css

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
.star {
2+
cursor:pointer;
3+
width:25px;
4+
height:25px;
5+
margin:2px;
6+
display:inline-block;
7+
background-color:grey;
8+
clip-path: polygon(
9+
50% 0%,
10+
63% 38%,
11+
100% 38%,
12+
69% 59%,
13+
82% 100%,
14+
50% 75%,
15+
18% 100%,
16+
31% 59%,
17+
0% 38%,
18+
37% 38%
19+
);
20+
}
21+
22+
.star.selected{
23+
background : yellow;
24+
}

chapter9/src/Star.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import './Star.css';
4+
5+
// class StarRating extends Component {
6+
7+
// }
8+
9+
const Star = ({selected=false, onClick=f=>f}) =>
10+
<div className={(selected) ? 'star selected' : 'star'} onClick={onClick}>
11+
</div>;
12+
13+
Star.propTypes = {
14+
selected : PropTypes.bool,
15+
onClick : PropTypes.func
16+
};
17+
18+
export default Star;

chapter9/src/StarRating.js

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import React, { Component } from 'react';
2+
import Star from './Star';
3+
import PropTypes from 'prop-types';
4+
5+
class StarRating extends Component {
6+
constructor(props) {
7+
super(props);
8+
this.state = {
9+
starsSelected : props.starsSelected || 0
10+
}
11+
this.change = this.change.bind(this);
12+
}
13+
static defaultProps = {
14+
totalStars : 5
15+
}
16+
static propTypes = {
17+
totalStars : PropTypes.number
18+
}
19+
change(starsSelected) {
20+
this.setState({starsSelected});
21+
}
22+
render() {
23+
const {totalStars} = this.props;
24+
const {starsSelected} = this.state;
25+
return (
26+
<div className="star-rating">
27+
{[...Array(totalStars)].map((n, i) =>
28+
<Star key={i}
29+
selected={i<starsSelected}
30+
onClick={()=>this.change(i+1)}
31+
/>
32+
)}
33+
<p>별점 : {starsSelected} / {totalStars}</p>
34+
</div>
35+
)
36+
}
37+
}
38+
39+
40+
export default StarRating;

chapter9/src/constants.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const constants = {
2+
SORT_COLORS : 'SORT_COLORS',
3+
ADD_COLOR : 'ADD_COLOR',
4+
RATE_COLOR : 'RATE_COLOR',
5+
REMOVE_COLOR : 'REMOVE_COLOR'
6+
}
7+
export default constants;

chapter9/src/index.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import React from 'react';
22
import ReactDOM from 'react-dom';
33
import './index.css';
44
import App from './App';
5+
import {createStore, combineReducers, applyMiddleware} from 'redux'
6+
import {colors, sort} from './reducers'
57
import * as serviceWorker from './serviceWorker';
68

7-
const colors = {
9+
const stateData = {
810
'colors' : [
911
{
1012
'id' : 'ieijfd3-34837fdn',
@@ -28,6 +30,22 @@ const colors = {
2830
};
2931

3032

33+
const logger = store => next => action => {
34+
let result;
35+
console.groupCollapsed('디스패칭', action.type);
36+
console.log('이전 상태', store.getState());
37+
result = next(action);
38+
console.log('다음 상태', store.getState());
39+
console.groupEnd();
40+
}
41+
42+
const saver = store => next => action => {
43+
let result = next(action);
44+
localStorage['redux-store'] = JSON.stringify(store.getState());
45+
return result;
46+
}
47+
48+
3149
const storeFactory = (initialState=stateData) =>
3250
applyMiddleware(logger, saver)(createStore)(
3351
combineReducers({colors, sort}),

chapter9/src/lib/array-helpers.js

+15-27
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,17 @@
1-
import PropTypes from 'prop-types'
2-
import '../../../stylesheets/Menu.scss'
3-
4-
const options = {
5-
date: "SORTED_BY_DATE",
6-
title: "SORTED_BY_TITLE",
7-
rating: "SORTED_BY_RATING"
8-
}
9-
10-
const SortMenu = ({ sort="SORTED_BY_DATE", onSelect=f=>f}) =>
11-
<nav className="menu">
12-
<h1>Sort Colors</h1>
13-
{Object.keys(options).map((item, i) =>
14-
<a key={i}
15-
href="#"
16-
className={(sort === options[item]) ? "selected" : null}
17-
onClick={e => {
18-
e.preventDefault()
19-
onSelect(options[item])
20-
}}>{item}</a>
21-
)}
22-
</nav>
23-
24-
SortMenu.propTypes = {
25-
sort: PropTypes.string,
26-
onSelect: PropTypes.func
1+
const sortBy = (type, field) => {
2+
switch (type) {
3+
case "date" :
4+
return (a, b) => new Date(b[field]) - new Date(a[field]);
5+
case "string" :
6+
return (a, b) => (a[field] < b[field]) ? -1 : 1;
7+
default:
8+
return (a, b) => b[field] - a[field];
9+
}
2710
}
2811

29-
export default SortMenu
12+
export const sortFunction = sort =>
13+
(sort === "SORTED_BY_TITLE") ?
14+
sortBy("string", "title") :
15+
(sort === "SORTED_BY_RATING") ?
16+
sortBy("number", "rating") :
17+
sortBy("date", "timestamp")

chapter9/src/reducers.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import C from './constants'
2+
export const color = (state ={}, action) => {
3+
switch(action.type) {
4+
case C.ADD_COLOR :
5+
return {
6+
id : action.id,
7+
title: action.title,
8+
color : action.color,
9+
timestamp : action.timestamp,
10+
rating : 0
11+
}
12+
break;
13+
case C.RATE_COLOR :
14+
return (state.id !== action.id) ?
15+
state : {...state, rating : action.rating}
16+
break;
17+
default : return state;
18+
}
19+
}
20+
21+
export const colors = (state = [], action) => {
22+
switch (action.type) {
23+
case C.ADD_COLOR :
24+
return [ ...state, color({}, action)];
25+
break;
26+
case C.RATE_COLOR :
27+
return state.map( c=> color(c, action));
28+
break;
29+
case C.REMOVE_COLOR :
30+
return state.filter(c=>c.id!==action.id);
31+
default: return state;
32+
}
33+
}
34+
35+
export const sort = (state = "SORTED_BY_DATE", action) => {
36+
switch(action.type) {
37+
case C.SORT_COLORS:
38+
return action.sortBy;
39+
break;
40+
default : return state;
41+
}
42+
}

chapter9/src/sortMenu.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react';
2+
3+
const options = {
4+
date: "SORTED_BY_DATE",
5+
title: "SORTED_BY_TITLE",
6+
rating: "SORTED_BY_RATING"
7+
}
8+
9+
const SortMenu = ({ sort="SORTED_BY_DATE", onSelect=f=>f}) =>
10+
<nav className="menu">
11+
<h1>Sort Colors</h1>
12+
{Object.keys(options).map((item, i) =>
13+
<a key={i}
14+
href="#"
15+
className={(sort === options[item]) ? "selected" : null}
16+
onClick={e => {
17+
e.preventDefault()
18+
onSelect(options[item])
19+
}}>{item}</a>
20+
)}
21+
</nav>
22+
23+
24+
export default SortMenu

chapter9/yarn.lock

+15-2
Original file line numberDiff line numberDiff line change
@@ -7832,7 +7832,7 @@ react-dev-utils@^9.0.0:
78327832
strip-ansi "5.2.0"
78337833
text-table "0.2.0"
78347834

7835-
7835+
react-dom@^16.8.6:
78367836
version "16.8.6"
78377837
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f"
78387838
integrity sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==
@@ -7910,7 +7910,7 @@ [email protected]:
79107910
optionalDependencies:
79117911
fsevents "2.0.6"
79127912

7913-
7913+
react@^16.8.6:
79147914
version "16.8.6"
79157915
resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"
79167916
integrity sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==
@@ -7999,6 +7999,14 @@ [email protected]:
79997999
dependencies:
80008000
minimatch "3.0.4"
80018001

8002+
redux@^4.0.1:
8003+
version "4.0.1"
8004+
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.1.tgz#436cae6cc40fbe4727689d7c8fae44808f1bfef5"
8005+
integrity sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg==
8006+
dependencies:
8007+
loose-envify "^1.4.0"
8008+
symbol-observable "^1.2.0"
8009+
80028010
regenerate-unicode-properties@^8.0.2:
80038011
version "8.0.2"
80048012
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.0.2.tgz#7b38faa296252376d363558cfbda90c9ce709662"
@@ -8956,6 +8964,11 @@ svgo@^1.0.0, svgo@^1.2.1:
89568964
unquote "~1.1.1"
89578965
util.promisify "~1.0.0"
89588966

8967+
symbol-observable@^1.2.0:
8968+
version "1.2.0"
8969+
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
8970+
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
8971+
89598972
symbol-tree@^3.2.2:
89608973
version "3.2.2"
89618974
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"

0 commit comments

Comments
 (0)