모양보기
bucket.js
const LOAD = 'bucket/LOAD';
const CREATE = 'bucket/CREATE';
const DELETE = "bucket/DELETE";
const UPDATE = "bucket/UPDATE";
const initialState = {
list: [
{text: "꽃 만들기", completed: false},
{text: "HTML, CSS(SCSS), JS", completed: false},
{text: "React, Vue, Angular", completed: false},
],
};
export const loadBucket = (bucket) => {
return {type: LOAD, bucket};
}
export const createBucket = (bucket) => {
return {type: CREATE, bucket}
}
export const deleteBucket = (bucket) => {
return {type: DELETE, bucket};
}
export const updateBucket= (bucket) => {
return {type: UPDATE, bucket};
}
export default function reducer(state = initialState, action) {
switch (action.type) {
case "bucket/LOAD": {
return state;
}
case "bucket/CREATE": {
const new_bucket_list = [...state.list, {text: action.bucket, completed: false}];
return {list: new_bucket_list};
}
case "bucket/DELETE": {
const bucket_list = state.list.filter((l, idx) => {
if(idx !== action.bucket) {
return l;
}
});
return {list: bucket_list};
}
case "bucket/UPDATE": {
const bucket_list = state.list.map((l, idx) => {
if(idx === action.bucket) {
return {...l, completed: true};
} else {
return l;
}
});
return {list: bucket_list};
}
default: return state;
}
}
import React from "react";
import BucketList from "./BucketList";
import styled from "styled-components";
import { withRouter } from 'react-router';
import { Route, Switch } from "react-router-dom";
import Detail from './Detail';
import NotFound from './NotFound';
import Progress from './Progress';
import { connect } from "react-redux";
import {loadBucket, createBucket} from "./redux/modules/bucket";
const mapStateToProps = (state) => {
return {bucket_list: state.bucket.list};
}
const mapDispathchToProps = (dispatch) => {
return {
load: () => {
dispatch(loadBucket());
},
create: (bucket) => {
dispatch(createBucket(bucket));
}
};
}
// 클래스형 컴포넌트는 이렇게 생겼습니다!
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
};
this.text = React.createRef();
}
componentDidMount() {
console.log(this.props);
}
addBucketList = () => {
const new_item = this.text.current.value;
this.props.create(new_item);
};
render() {
return (
<div className="App">
<Container>
<Title>내 버킷리스트</Title>
<Progress/>
<Line />
<Switch>
<Route path="/" exact component={BucketList} />
<Route path="/detail/:index" component={Detail} />
<Route component={NotFound} />
</Switch>
</Container>
<Input>
<input type="text" ref={this.text} />
<button onClick={this.addBucketList}>추가하기</button>
</Input>
</div>
);
}
}
const Input = styled.div`
max-width: 350px;
min-height: 10vh;
background-color: #fff;
padding: 16px;
margin: 20px auto;
border-radius: 5px;
border: 1px solid #ddd;
`;
const Container = styled.div`
max-width: 350px;
min-height: 80vh;
background-color: #fff;
padding: 16px;
margin: 20px auto;
border-radius: 5px;
border: 1px solid #ddd;
`;
const Title = styled.h1`
color: #e0a83f;
text-align: center;
`;
const Line = styled.hr`
margin: 16px 0px;
border: 1px dotted #e0a83f;
`;
export default connect(mapStateToProps, mapDispathchToProps)(withRouter(App));
import React from "react";
import styled from "styled-components";
import { useSelector, useDispatch } from 'react-redux';
const BucketList = (props) => {
const bucket_list = useSelector(state => state.bucket.list);
console.log(bucket_list);
return (
<ListStyle>
{bucket_list.map((list, index) => {
return (
<ItemStyle
className="list_item"
color={list.completed? "orange" : "aliceblue"}
key={index}
onClick={() => {
props.history.push("/detail/"+index);
}}
>
{list.text}
</ItemStyle>
);
})}
</ListStyle>
);
};
const ListStyle = styled.div`
display: flex;
flex-direction: column;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
`;
const ItemStyle = styled.div`
padding: 16px;
margin: 8px;
background-color: ${(props) => props.color};
`;
export default BucketList;
import React from "react";
import { useSelector, useDispatch } from 'react-redux';
import {deleteBucket, updateBucket} from "./redux/modules/bucket";
const Detail = (props) => {
const dispatch = useDispatch();
const bucket_list = useSelector((state) => state.bucket.list);
console.log(bucket_list, props);
const bucket_index = parseInt(props.match.params.index);
return (
<div>
<h1>{bucket_list[bucket_index].text}</h1>
<button onClick={() => {
dispatch(deleteBucket(bucket_index));
props.history.goBack();
}}>삭제하기</button>
<button onClick={() => {
dispatch(updateBucket(bucket_list));
props.history.goBack();
}}>완료하기</button>
</div>
);
};
export default Detail;
import React from "react";
import styled from 'styled-components';
import { useSelector } from 'react-redux';
const Progress = (props) => {
const bucket_list = useSelector(state => state.bucket.list);
let count = 0;
bucket_list.map((l, idx) => {
if(l.completed) {
count++;
}
});
return (
<ProgressBar>
<HighLight width={(count / bucket_list.length) * 100 + "%"}></HighLight>
</ProgressBar>
);
}
const ProgressBar = styled.div`
background: #eee;
width: 100%;
height: 40px;
`;
const HighLight = styled.div`
background: orange;
heigth: 40px;
width: ${(props) => props.width};
transition: width 1s;
`;
export default Progress;