From 5774e6343ef1109c38e02e9ab8ec565530ffcd49 Mon Sep 17 00:00:00 2001 From: eunjoo jung Date: Fri, 25 Sep 2020 20:49:18 +0900 Subject: [PATCH 1/4] week3 upload --- backend/todo/urls.py | 2 +- package.json | 8 +- src/App.js | 12 ++- src/components/Todo/Todo.js | 5 +- src/containers/TodoList/NewTodo/NewTodo.js | 24 +++-- .../TodoList/RealDetail/RealDetail.js | 36 +++++++- src/containers/TodoList/TodoList.js | 79 +++++++++++----- src/index.js | 25 +++++- src/store/actions/actionTypes.js | 5 ++ src/store/actions/index.js | 4 + src/store/actions/todo.js | 90 +++++++++++++++++++ src/store/reducers/todo.js | 53 +++++++++++ yarn.lock | 72 +++++++++++++++ 13 files changed, 375 insertions(+), 40 deletions(-) create mode 100644 src/store/actions/actionTypes.js create mode 100644 src/store/actions/index.js create mode 100644 src/store/actions/todo.js create mode 100644 src/store/reducers/todo.js diff --git a/backend/todo/urls.py b/backend/todo/urls.py index 60f5822..5226177 100644 --- a/backend/todo/urls.py +++ b/backend/todo/urls.py @@ -4,5 +4,5 @@ urlpatterns = [ path('', views.index), - path('', views.index), + path('/', views.index), ] diff --git a/package.json b/package.json index 4488cb3..23948ff 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,18 @@ "name": "swppfront", "version": "0.1.0", "private": true, + "proxy": "http://localhost:8000", "dependencies": { + "axios": "^0.20.0", + "connected-react-router": "^6.8.0", "react": "^16.9.0", "react-dom": "^16.9.0", + "react-redux": "^7.2.1", "react-router": "^5.0.1", "react-router-dom": "^5.0.1", - "react-scripts": "3.1.1" + "react-scripts": "3.1.1", + "redux": "^4.0.5", + "redux-thunk": "^2.3.0" }, "scripts": { "start": "react-scripts start", diff --git a/src/App.js b/src/App.js index 610cd4b..d8f23af 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,6 @@ import React from 'react'; import './App.css'; +import {ConnectedRouter} from 'connected-react-router'; import TodoList from './containers/TodoList/TodoList'; import RealDetail from './containers/TodoList/RealDetail/RealDetail'; @@ -7,19 +8,22 @@ import NewTodo from './containers/TodoList/NewTodo/NewTodo'; import { BrowserRouter, Route, Redirect, Switch } from 'react-router-dom'; -function App() { + + + +function App(props) { return ( - +
- } /> + } />

Not Found

} />
-
+ ); } diff --git a/src/components/Todo/Todo.js b/src/components/Todo/Todo.js index 9c80927..c9dcacb 100644 --- a/src/components/Todo/Todo.js +++ b/src/components/Todo/Todo.js @@ -3,15 +3,16 @@ import React from 'react'; import './Todo.css'; const Todo = (props) => { - return (
+ onClick={props.clickDetail}> {props.title}
{props.done &&
} + +
); }; diff --git a/src/containers/TodoList/NewTodo/NewTodo.js b/src/containers/TodoList/NewTodo/NewTodo.js index 59e7930..4993604 100644 --- a/src/containers/TodoList/NewTodo/NewTodo.js +++ b/src/containers/TodoList/NewTodo/NewTodo.js @@ -1,7 +1,10 @@ import React, { Component } from 'react'; +import {connect} from 'react-redux'; +import {render} from 'react-dom'; +import * as actionTypes from '../../../store/actions/actionTypes'; import { Redirect } from 'react-router-dom'; - +import * as actionCreators from '../../../store/actions/index'; import './NewTodo.css'; class NewTodo extends Component { @@ -12,12 +15,13 @@ class NewTodo extends Component { } postTodoHandler = () => { - const data = + const data = { title: this.state.title, content: this.state.content } - alert('submitted' + data.title); - // this.props.history.push('/todos'); + // // this.props.history.push('/todos'); this.props.history.goBack(); this.setState({ submitted: true }); + this.props.onStoreTodo(this.state.title, this.state.content); + alert("new todo submitted"); } render() { @@ -36,7 +40,7 @@ class NewTodo extends Component { > @@ -45,4 +49,12 @@ class NewTodo extends Component { } } -export default NewTodo; \ No newline at end of file +const mapDispatchToProps = dispatch => { + return { + onStoreTodo: (title, content)=> { + // dispatch(actionCreators.postTodo({title:title, cotent:content})) + dispatch({type:actionTypes.ADD_TODO, title, content}) + } + }; +}; +export default connect(null, mapDispatchToProps)(NewTodo); \ No newline at end of file diff --git a/src/containers/TodoList/RealDetail/RealDetail.js b/src/containers/TodoList/RealDetail/RealDetail.js index 89500a3..e719c1e 100644 --- a/src/containers/TodoList/RealDetail/RealDetail.js +++ b/src/containers/TodoList/RealDetail/RealDetail.js @@ -1,23 +1,38 @@ import React, { Component } from 'react'; - +import {connect} from 'react-redux'; import './RealDetail.css'; +import * as actionCreators from '../../../store/actions/index'; +import * as actionTypes from '../../../store/actions/actionTypes'; class RealDetail extends Component { + componentDidMount() { + this.props.onGetTodo(parseInt(this.props.match.params.id)); + } + render() { + let title = '', content = ''; + if (this.props.selectedTodo) { + title= this.props.selectedTodo.title; + content = this.props.selectedTodo.content; + } + // const { content, title } = this.props.selectedTodo; return ( +
Name:
+ {this.props.selectedTodo.title}
- Content: + Content:
+ {this.props.selectedTodo.content}
@@ -25,4 +40,19 @@ class RealDetail extends Component { } }; -export default RealDetail; \ No newline at end of file +const mapStateToProps = state => { + return { + selectedTodo: state.td.selectedTodo, + }; +}; + +const mapDispatchToProps = dispatch => { + return { + onGetTodo: (id) => + dispatch({type: actionTypes.GET_TODO, targetID: id}), + // dispatch(actionCreators.onGetTodo(id)), + // dispatch(actionCreators.getTodo(id)), + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(RealDetail); \ No newline at end of file diff --git a/src/containers/TodoList/TodoList.js b/src/containers/TodoList/TodoList.js index 6cb72c1..1aa0117 100644 --- a/src/containers/TodoList/TodoList.js +++ b/src/containers/TodoList/TodoList.js @@ -6,44 +6,64 @@ import TodoDetail from '../../components/TodoDetail/TodoDetail'; import { NavLink } from 'react-router-dom'; import './TodoList.css'; +import {connect} from 'react-redux'; +import * as actionTypes from '../../store/actions/actionTypes'; +import {withRouter} from 'react-router'; +import axios from 'axios'; +import * as actionCreators from '../../store/actions/index'; +//chrome extension에서 redux 탭이 있는지 확인한다. + + + +const mapStateToProps = state => { + return { + // debugger 를 통해서 breakpoint를 만든다. + storedTodos: state.td.todos, + selectedTodo: state.td.selectedTodo + }; +} class TodoList extends Component { - state = { - todos: [ - { id: 1, title: 'SWPP', content: 'take swpp class', done: true }, - { id: 2, title: 'Movie', content: 'watch movie', done: false }, - { id: 3, title: 'Dinner', content: 'eat dinner', done: false } - ], - selectedTodo: null, + componentDidMount() { + axios.get('/api/todo/') + .then(result => console.log(result.data)) + .then(err => console.log(err)); + return this.props.onGetAll(); } clickTodoHandler = (td) => { - if (this.state.selectedTodo === td) { - this.setState({ ...this.state, selectedTodo: null }); - } else { - this.setState({ ...this.state, selectedTodo: td }); - } + // if (this.state.selectedTodo === td) { + // this.setState({ ...this.state, selectedTodo: null }); + // } else { + // this.setState({ ...this.state, selectedTodo: td }); + // } + this.props.history.push(`/todos/${td.id}`); + // `/todos/${td.id}` } render() { - const todos = this.state.todos.map(td => { + const todos = this.props.storedTodos.map((td) => { + return ( this.clickTodoHandler(td)} + clickDetail={() => this.clickTodoHandler(td)} + clickDone={() => this.props.onToggleTodo(td.id)} + clickDelete={() => this.props.onDeleteTodo(td.id)} /> ); }); - let todo = null; - if (this.state.selectedTodo) { - todo = - } + // let todo = null; + // if (this.props.selectedTodo) { + // todo = + // } return (
@@ -52,11 +72,26 @@ class TodoList extends Component {
{todos}
- {todo} + {/* {todo} */} New Todo
) } } -export default TodoList; \ No newline at end of file +const mapDispatchToProps = dispatch => { + return { + onToggleTodo: (id) => + // dispatch({type:actionTypes.TOGGLE_DONE, targetID:id}), + dispatch(actionCreators.toggleTodo(id)), + onDeleteTodo: (id) => + // dispatch({type:actionTypes.DELETE_TODO, targetID:id}), + dispatch(actionCreators.deleteTodo(id)), + // onToggleTodo: (id) => + // dispatch(actionCreators.toggleTodo(id)), + onGetAll: () => + dispatch(actionCreators.getTodos()), + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(withRouter(TodoList)); \ No newline at end of file diff --git a/src/index.js b/src/index.js index 87d1be5..901a5d9 100644 --- a/src/index.js +++ b/src/index.js @@ -3,9 +3,32 @@ import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import * as serviceWorker from './serviceWorker'; +import {Provider} from 'react-redux'; -ReactDOM.render(, document.getElementById('root')); +import {createStore, combineReducers, applyMiddleware, compose } from 'redux'; +import todoReducer from './store/reducers/todo'; +import thunk from 'redux-thunk'; +import {connectRouter, routerMiddleware} from 'connected-react-router'; +import {createBrowserHistory} from 'history'; + +const history = createBrowserHistory(); +const rootReducer = combineReducers({ + td: todoReducer, router:connectRouter(history) +}); + +// const store = createStore((state = {}, action) => state); // TODO +// +// const composeEnhancers = window.__REDUX.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; +// const store = createStore(rootReducer, applyMiddleware(logger, thunk, routerMiddleware(history))) ; +const store = createStore(rootReducer, applyMiddleware(thunk)); +// applyMiddleware(thunk, routerMiddleware(history)) +// store = createStore(combineReducer(rootReducer, -----)) 섞어서 사용할 수 있다. +//window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()) + +ReactDOM.render( + , + document.getElementById('root')); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA diff --git a/src/store/actions/actionTypes.js b/src/store/actions/actionTypes.js new file mode 100644 index 0000000..b954b80 --- /dev/null +++ b/src/store/actions/actionTypes.js @@ -0,0 +1,5 @@ +export const GET_ALL = 'GET_ALL'; +export const GET_TODO = 'GET_TODO'; +export const TOGGLE_DONE = 'TOGGLE_DONE'; +export const DELETE_TODO = 'DELETE_TODO'; +export const ADD_TODO = 'ADD_TODO'; \ No newline at end of file diff --git a/src/store/actions/index.js b/src/store/actions/index.js new file mode 100644 index 0000000..f22b3e3 --- /dev/null +++ b/src/store/actions/index.js @@ -0,0 +1,4 @@ + +export { + getTodos, postTodo, deleteTodo, toggleTodo, getTodo +} from './todo'; \ No newline at end of file diff --git a/src/store/actions/todo.js b/src/store/actions/todo.js new file mode 100644 index 0000000..9d8b425 --- /dev/null +++ b/src/store/actions/todo.js @@ -0,0 +1,90 @@ +import * as actionTypes from './actionTypes'; +import axios from 'axios'; +// import {push} from 'connected-react-router'; + +export const getTodos_ = (todos) => { + return {type: actionTypes.GET_ALL, todos:todos}; +}; + +export const getTodos = () => { + return dispatch => { + return axios.get('/api/todo/') + .then(res => dispatch(getTodos_(res.data))); + } +}; + +export const deleteTodo_ = (id) => { + return { + type: actionTypes.DELETE_TODO, + targetID: id + }; +}; + +export const deleteTodo = (id) => { + return (dispatch) => { + return axios.delete('/api/todo/' + id) + .then(res => { + dispatch(deleteTodo_(id)); + }); + }; +}; + +export const toggleTodo_ = (id) => { + return { + type: actionTypes.TOGGLE_DONE, + targetID: id + }; +}; + +export const toggleTodo = (id) => { + return (dispatch) => { + return axios.put('/api/todo/' + id) + .then(res => { + dispatch(toggleTodo_(id)); + }); + }; +}; + +export const postTodo_ = (td) => { + return { + type: actionTypes.ADD_TODO, + id: td.id, + title: td.title, + content: td.content + }; +}; + +export const postTodo = (td) => { + return (dispatch) => { + // dispatch(startPostTodo); + + axios.post('/api/todo/' + td) + // .then(res => { + // dispatch(postTodo_(res.data)); + // }); + .then(res => { dispatch(postTodo_(res.data)) + // .then(() => { dispatch(push('/todos')) + // dispatch(successPostTodo(res.data)); + }); + // .catch(err => { + // // dispatch(failurePostTodo(err)); + // }); + }; +}; +export const getTodo_ = (todo) => { + return { + type: actionTypes.GET_TODO, + // title: todo.title, + // content: todo.content, + target: todo + }; +}; + +export const getTodo = (id) => { + return (dispatch) => { + return axios.get('/api/todo/' + id) + .then(res => { + dispatch(getTodo_(res.data)); + }); + }; +}; diff --git a/src/store/reducers/todo.js b/src/store/reducers/todo.js new file mode 100644 index 0000000..b34883d --- /dev/null +++ b/src/store/reducers/todo.js @@ -0,0 +1,53 @@ +import {ADD_TODO, DELETE_TODO, TOGGLE_DONE, GET_TODO, GET_ALL} from '../actions/actionTypes'; +// ADD_TODO DELETE_TODO 등등이 *에 해당한다. +//import ADD_TODO 이런 식으로 하면, case ADD_TODO ㅣㅇ렇게 하면 된다. + +const initialState = { + todos: [ + // { id: 1, title: 'SWPP', content: 'take swpp class', done: true }, + // { id: 2, title: 'Movie', content: 'watch movie', done: false }, + // { id: 3, title: 'Dinner', content: 'eat dinner', done: false } + ], + selectedTodo: null, +}; + +const reducer = (state = initialState, action) => { + switch (action.type) { + case ADD_TODO: + const newTodo = { + id: state.todos.length +1, + title: action.title, content:action.content, done: action.done + } + // state.todos.push(newTodo) // BAD + // state.todos.concat(newTodo) 뒤에 나오는 인자를 붙여서 새로운 리스트를 만들어준다 + // 두번째 방법은 사용할 수 있다 ㅎㅎㅎㅎㅎㅎㅎㅎ + + return {...state, todos: [ ...state.todos, newTodo]}; + // action.targetID => parseInt(action.targetID) + case DELETE_TODO: + const filtered = state.todos.filter(td => td.id !== action.targetID); + return {...state, todos: filtered}; + + case TOGGLE_DONE: + const modified = state.todos.map((todo) => { + if(todo.id === action.targetID) { + return { ...todo, done: !todo.done}; + } else { + return {...todo}; // todo; + } + }); + return { ...state, todos: modified }; + + case GET_TODO: + // const selectedTodo = state.todos.find(td => td.id === action.targetId); + return {...state, selectedTodo: action.target}; + + case GET_ALL: + return {...state, todos: action.todos}; + default: + break; + } + return state; +}; + +export default reducer; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 54cccc1..584c215 100644 --- a/yarn.lock +++ b/yarn.lock @@ -770,6 +770,13 @@ dependencies: regenerator-runtime "^0.13.2" +"@babel/runtime@^7.5.5": + version "7.11.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" + integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" @@ -1748,6 +1755,13 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== +axios@^0.20.0: + version "0.20.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd" + integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA== + dependencies: + follow-redirects "^1.10.0" + axobject-query@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9" @@ -2551,6 +2565,13 @@ connect-history-api-fallback@^1.3.0: resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== +connected-react-router@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/connected-react-router/-/connected-react-router-6.8.0.tgz#ddc687b31d498322445d235d660798489fa56cae" + integrity sha512-E64/6krdJM3Ag3MMmh2nKPtMbH15s3JQDuaYJvOVXzu6MbHbDyIvuwLOyhQIuP4Om9zqEfZYiVyflROibSsONg== + dependencies: + prop-types "^15.7.2" + console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" @@ -4005,6 +4026,11 @@ follow-redirects@^1.0.0: dependencies: debug "^3.2.6" +follow-redirects@^1.10.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" + integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== + for-in@^0.1.3: version "0.1.8" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" @@ -4429,6 +4455,13 @@ hoist-non-react-statics@^3.1.0: dependencies: react-is "^16.7.0" +hoist-non-react-statics@^3.3.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + hosted-git-info@^2.1.4: version "2.8.4" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.4.tgz#44119abaf4bc64692a16ace34700fed9c03e2546" @@ -7944,6 +7977,22 @@ react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.9.0.tgz#21ca9561399aad0ff1a7701c01683e8ca981edcb" integrity sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw== +react-is@^16.9.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-redux@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.1.tgz#8dedf784901014db2feca1ab633864dee68ad985" + integrity sha512-T+VfD/bvgGTUA74iW9d2i5THrDQWbweXP0AVNI8tNd1Rk5ch1rnMiJkDD67ejw7YBKM4+REvcvqRuWJb7BLuEg== + dependencies: + "@babel/runtime" "^7.5.5" + hoist-non-react-statics "^3.3.0" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^16.9.0" + react-router-dom@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.0.1.tgz#ee66f4a5d18b6089c361958e443489d6bab714be" @@ -8122,6 +8171,19 @@ recursive-readdir@2.2.2: dependencies: minimatch "3.0.4" +redux-thunk@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" + integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw== + +redux@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" + integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w== + dependencies: + loose-envify "^1.4.0" + symbol-observable "^1.2.0" + regenerate-unicode-properties@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" @@ -8144,6 +8206,11 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== +regenerator-runtime@^0.13.4: + version "0.13.7" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" + integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== + regenerator-transform@^0.14.0: version "0.14.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" @@ -9115,6 +9182,11 @@ svgo@^1.0.0, svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-observable@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + symbol-tree@^3.2.2: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" From 84f9a39f4bae1e2e89fd9ecee372fe08cc7f4493 Mon Sep 17 00:00:00 2001 From: eunjoo jung Date: Fri, 25 Sep 2020 20:58:30 +0900 Subject: [PATCH 2/4] typo updated --- src/containers/TodoList/TodoList.js | 2 +- src/store/actions/todo.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/containers/TodoList/TodoList.js b/src/containers/TodoList/TodoList.js index 1aa0117..e13b3d6 100644 --- a/src/containers/TodoList/TodoList.js +++ b/src/containers/TodoList/TodoList.js @@ -37,7 +37,7 @@ class TodoList extends Component { // } else { // this.setState({ ...this.state, selectedTodo: td }); // } - this.props.history.push(`/todos/${td.id}`); + this.props.history.push(`/todos/${td.id}/`); // `/todos/${td.id}` } diff --git a/src/store/actions/todo.js b/src/store/actions/todo.js index 9d8b425..e6001f2 100644 --- a/src/store/actions/todo.js +++ b/src/store/actions/todo.js @@ -8,7 +8,7 @@ export const getTodos_ = (todos) => { export const getTodos = () => { return dispatch => { - return axios.get('/api/todo/') + return axios.get(`/api/todo/`) .then(res => dispatch(getTodos_(res.data))); } }; @@ -22,7 +22,7 @@ export const deleteTodo_ = (id) => { export const deleteTodo = (id) => { return (dispatch) => { - return axios.delete('/api/todo/' + id) + return axios.delete(`/api/todo/${id}/`) .then(res => { dispatch(deleteTodo_(id)); }); @@ -38,7 +38,7 @@ export const toggleTodo_ = (id) => { export const toggleTodo = (id) => { return (dispatch) => { - return axios.put('/api/todo/' + id) + return axios.put(`/api/todo/${id}/`) .then(res => { dispatch(toggleTodo_(id)); }); @@ -58,7 +58,7 @@ export const postTodo = (td) => { return (dispatch) => { // dispatch(startPostTodo); - axios.post('/api/todo/' + td) + axios.post(`/api/todo/${td}/`) // .then(res => { // dispatch(postTodo_(res.data)); // }); @@ -82,7 +82,7 @@ export const getTodo_ = (todo) => { export const getTodo = (id) => { return (dispatch) => { - return axios.get('/api/todo/' + id) + return axios.get(`/api/todo/${id}`) .then(res => { dispatch(getTodo_(res.data)); }); From 128e17940a02b3aad14294314183e77e83214741 Mon Sep 17 00:00:00 2001 From: eunjoo jung Date: Fri, 25 Sep 2020 21:14:22 +0900 Subject: [PATCH 3/4] typo updated2 --- backend/db.sqlite3 | Bin 139264 -> 139264 bytes .../TodoList/RealDetail/RealDetail.js | 8 ++++---- src/containers/TodoList/TodoList.js | 2 +- src/index.js | 2 +- src/store/actions/todo.js | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/db.sqlite3 b/backend/db.sqlite3 index 6265512928054730f8b4b68b150b9ac9a105f3d9..491e1c7cfe144c39f7587580ca0e9d31c2bf020e 100644 GIT binary patch delta 63 zcmZoTz|nAkV}dke`a~IL)^r9v6NSc<))dCADNJ+u`T3tQF!AqT;6Km50|=LI7EGAM SKYf)vlMM?41B28=M==0(84`E^ delta 82 zcmV-Y0ImOkzzBfA2#^~ATag??1zP|vI0%7cg=7J>WCEQJ4*&oF0}r?W59SZg54aDf ovk_pL50|PR0z4WR2n7HYD+yCqP*8MXYh@sFcW`hZV{Bn_bJ`0S7XSbN diff --git a/src/containers/TodoList/RealDetail/RealDetail.js b/src/containers/TodoList/RealDetail/RealDetail.js index e719c1e..ded0d0f 100644 --- a/src/containers/TodoList/RealDetail/RealDetail.js +++ b/src/containers/TodoList/RealDetail/RealDetail.js @@ -24,7 +24,7 @@ class RealDetail extends Component { Name:
- {this.props.selectedTodo.title} + {title}
@@ -32,7 +32,7 @@ class RealDetail extends Component { Content:
- {this.props.selectedTodo.content} + {content}
@@ -49,9 +49,9 @@ const mapStateToProps = state => { const mapDispatchToProps = dispatch => { return { onGetTodo: (id) => - dispatch({type: actionTypes.GET_TODO, targetID: id}), + // dispatch({type: actionTypes.GET_TODO, targetID: id}), // dispatch(actionCreators.onGetTodo(id)), - // dispatch(actionCreators.getTodo(id)), + dispatch(actionCreators.getTodo(id)), }; }; diff --git a/src/containers/TodoList/TodoList.js b/src/containers/TodoList/TodoList.js index e13b3d6..fc34739 100644 --- a/src/containers/TodoList/TodoList.js +++ b/src/containers/TodoList/TodoList.js @@ -37,7 +37,7 @@ class TodoList extends Component { // } else { // this.setState({ ...this.state, selectedTodo: td }); // } - this.props.history.push(`/todos/${td.id}/`); + this.props.history.push('/todos/' + td.id); // `/todos/${td.id}` } diff --git a/src/index.js b/src/index.js index 901a5d9..5e0694a 100644 --- a/src/index.js +++ b/src/index.js @@ -21,7 +21,7 @@ const rootReducer = combineReducers({ // // const composeEnhancers = window.__REDUX.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // const store = createStore(rootReducer, applyMiddleware(logger, thunk, routerMiddleware(history))) ; -const store = createStore(rootReducer, applyMiddleware(thunk)); +const store = createStore(rootReducer, applyMiddleware(thunk, routerMiddleware(history))); // applyMiddleware(thunk, routerMiddleware(history)) // store = createStore(combineReducer(rootReducer, -----)) 섞어서 사용할 수 있다. //window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()) diff --git a/src/store/actions/todo.js b/src/store/actions/todo.js index e6001f2..f936fa6 100644 --- a/src/store/actions/todo.js +++ b/src/store/actions/todo.js @@ -8,7 +8,7 @@ export const getTodos_ = (todos) => { export const getTodos = () => { return dispatch => { - return axios.get(`/api/todo/`) + return axios.get('/api/todo/') .then(res => dispatch(getTodos_(res.data))); } }; From e1d3245942a79c0336052b6100359fd7824c0bac Mon Sep 17 00:00:00 2001 From: eunjoo jung Date: Sat, 26 Sep 2020 20:25:43 +0900 Subject: [PATCH 4/4] logger & middleware used + typo updated --- backend/db.sqlite3 | Bin 139264 -> 139264 bytes backend/todo/views.py | 1 + package.json | 1 + src/App.js | 4 +-- src/containers/TodoList/NewTodo/NewTodo.js | 28 +++++++++--------- .../TodoList/RealDetail/RealDetail.js | 2 +- src/containers/TodoList/TodoList.js | 9 +++--- src/index.js | 23 ++++++++++---- src/store/actions/todo.js | 13 ++++---- src/store/reducers/todo.js | 11 ++++--- 10 files changed, 57 insertions(+), 35 deletions(-) diff --git a/backend/db.sqlite3 b/backend/db.sqlite3 index 491e1c7cfe144c39f7587580ca0e9d31c2bf020e..56cc4dd19bd7635c01a0b264deac454bf0bfb2d8 100644 GIT binary patch delta 122 zcmZoTz|nAkV}dke@kAMC#^Q|$QTlBB;;hWZjMG0lF$y zJNQ5IPunb*(8jN%z|YDcYs~RxW`iCGyqU4&ZF9q$84a(ym%Q%oP cJAiQcX2FD6{Ct88$YA;oc_u?fsfmta01=55u>b%7 diff --git a/backend/todo/views.py b/backend/todo/views.py index 598af14..272e002 100644 --- a/backend/todo/views.py +++ b/backend/todo/views.py @@ -28,6 +28,7 @@ def index(request, id=None): if request.method == 'POST': try: body = request.body.decode() + print("hello", body) title = json.loads(body)['title'] content = json.loads(body)['content'] except (KeyError, JSONDecodeError) as e: diff --git a/package.json b/package.json index 23948ff..55aa44a 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "proxy": "http://localhost:8000", + "dependencies": { "axios": "^0.20.0", "connected-react-router": "^6.8.0", diff --git a/src/App.js b/src/App.js index d8f23af..6de3aac 100644 --- a/src/App.js +++ b/src/App.js @@ -6,7 +6,7 @@ import TodoList from './containers/TodoList/TodoList'; import RealDetail from './containers/TodoList/RealDetail/RealDetail'; import NewTodo from './containers/TodoList/NewTodo/NewTodo'; -import { BrowserRouter, Route, Redirect, Switch } from 'react-router-dom'; +import {Route, Redirect, Switch } from 'react-router-dom'; @@ -16,7 +16,7 @@ function App(props) {
- } /> + } /> diff --git a/src/containers/TodoList/NewTodo/NewTodo.js b/src/containers/TodoList/NewTodo/NewTodo.js index 4993604..80ae69c 100644 --- a/src/containers/TodoList/NewTodo/NewTodo.js +++ b/src/containers/TodoList/NewTodo/NewTodo.js @@ -1,9 +1,9 @@ import React, { Component } from 'react'; import {connect} from 'react-redux'; -import {render} from 'react-dom'; +// import {render} from 'react-dom'; -import * as actionTypes from '../../../store/actions/actionTypes'; -import { Redirect } from 'react-router-dom'; +// import * as actionTypes from '../../../store/actions/actionTypes'; +// import { Redirect } from 'react-router-dom'; import * as actionCreators from '../../../store/actions/index'; import './NewTodo.css'; @@ -15,20 +15,20 @@ class NewTodo extends Component { } postTodoHandler = () => { - const data = - { title: this.state.title, content: this.state.content } + // const data = + // { title: this.state.title, content: this.state.content } // // this.props.history.push('/todos'); - this.props.history.goBack(); - this.setState({ submitted: true }); + // this.props.history.goBack(); + // this.setState({ submitted: true }); this.props.onStoreTodo(this.state.title, this.state.content); - alert("new todo submitted"); + // alert("new todo submitted"); } render() { - let redirect = null; - if (this.state.submitted) { - redirect = - } + // let redirect = null; + // if (this.state.submitted) { + // redirect = + // } return (

Add a New Todo!

@@ -52,8 +52,8 @@ class NewTodo extends Component { const mapDispatchToProps = dispatch => { return { onStoreTodo: (title, content)=> { - // dispatch(actionCreators.postTodo({title:title, cotent:content})) - dispatch({type:actionTypes.ADD_TODO, title, content}) + dispatch(actionCreators.postTodo({title:title, content:content})) + // dispatch({type:actionTypes.ADD_TODO, title, content}) } }; }; diff --git a/src/containers/TodoList/RealDetail/RealDetail.js b/src/containers/TodoList/RealDetail/RealDetail.js index ded0d0f..d0c9caf 100644 --- a/src/containers/TodoList/RealDetail/RealDetail.js +++ b/src/containers/TodoList/RealDetail/RealDetail.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import {connect} from 'react-redux'; import './RealDetail.css'; import * as actionCreators from '../../../store/actions/index'; -import * as actionTypes from '../../../store/actions/actionTypes'; +// import * as actionTypes from '../../../store/actions/actionTypes'; class RealDetail extends Component { componentDidMount() { diff --git a/src/containers/TodoList/TodoList.js b/src/containers/TodoList/TodoList.js index fc34739..433449d 100644 --- a/src/containers/TodoList/TodoList.js +++ b/src/containers/TodoList/TodoList.js @@ -1,13 +1,13 @@ import React, { Component } from 'react'; import Todo from '../../components/Todo/Todo'; -import TodoDetail from '../../components/TodoDetail/TodoDetail'; +// import TodoDetail from '../../components/TodoDetail/TodoDetail'; import { NavLink } from 'react-router-dom'; import './TodoList.css'; import {connect} from 'react-redux'; -import * as actionTypes from '../../store/actions/actionTypes'; +// import * as actionTypes from '../../store/actions/actionTypes'; import {withRouter} from 'react-router'; import axios from 'axios'; import * as actionCreators from '../../store/actions/index'; @@ -28,7 +28,7 @@ class TodoList extends Component { axios.get('/api/todo/') .then(result => console.log(result.data)) .then(err => console.log(err)); - return this.props.onGetAll(); + this.props.onGetAll(); } clickTodoHandler = (td) => { @@ -48,8 +48,9 @@ class TodoList extends Component { this.clickTodoHandler(td)} + // clicked={() => this.clickTodoHandler(td)} clickDetail={() => this.clickTodoHandler(td)} clickDone={() => this.props.onToggleTodo(td.id)} clickDelete={() => this.props.onDeleteTodo(td.id)} diff --git a/src/index.js b/src/index.js index 5e0694a..e4c14ec 100644 --- a/src/index.js +++ b/src/index.js @@ -5,7 +5,7 @@ import App from './App'; import * as serviceWorker from './serviceWorker'; import {Provider} from 'react-redux'; -import {createStore, combineReducers, applyMiddleware, compose } from 'redux'; +import {createStore, combineReducers, applyMiddleware, compose} from 'redux'; import todoReducer from './store/reducers/todo'; import thunk from 'redux-thunk'; import {connectRouter, routerMiddleware} from 'connected-react-router'; @@ -19,12 +19,25 @@ const rootReducer = combineReducers({ // const store = createStore((state = {}, action) => state); // TODO // -// const composeEnhancers = window.__REDUX.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; +const logger = store => { + return next => { + return action => { + console.log('[Middleware] Dispatching', action); + const reusult = next(action); + console.log('[Middleware] Next State', store.getState()); + return reusult; + } + } +} +const composeEnhancers = window.__REDUX__REDUX_DEVTOOLS_EXTENSION_COMPOSE__||compose; // const store = createStore(rootReducer, applyMiddleware(logger, thunk, routerMiddleware(history))) ; -const store = createStore(rootReducer, applyMiddleware(thunk, routerMiddleware(history))); +const store = createStore(rootReducer, + composeEnhancers( + applyMiddleware(logger, thunk, routerMiddleware(history))) + ); + // applyMiddleware(thunk, routerMiddleware(history))); // applyMiddleware(thunk, routerMiddleware(history)) -// store = createStore(combineReducer(rootReducer, -----)) 섞어서 사용할 수 있다. -//window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()) +// const store = createStore(rootReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()); ReactDOM.render( , diff --git a/src/store/actions/todo.js b/src/store/actions/todo.js index f936fa6..3479d7b 100644 --- a/src/store/actions/todo.js +++ b/src/store/actions/todo.js @@ -1,6 +1,6 @@ import * as actionTypes from './actionTypes'; import axios from 'axios'; -// import {push} from 'connected-react-router'; +import {push} from 'connected-react-router'; export const getTodos_ = (todos) => { return {type: actionTypes.GET_ALL, todos:todos}; @@ -57,12 +57,14 @@ export const postTodo_ = (td) => { export const postTodo = (td) => { return (dispatch) => { // dispatch(startPostTodo); - - axios.post(`/api/todo/${td}/`) + return axios.post('/api/todo/', td) // .then(res => { // dispatch(postTodo_(res.data)); // }); - .then(res => { dispatch(postTodo_(res.data)) + + .then(res => { + dispatch(postTodo_(res.data)); + dispatch(push('/todos/')); // .then(() => { dispatch(push('/todos')) // dispatch(successPostTodo(res.data)); }); @@ -71,6 +73,7 @@ export const postTodo = (td) => { // }); }; }; + export const getTodo_ = (todo) => { return { type: actionTypes.GET_TODO, @@ -82,7 +85,7 @@ export const getTodo_ = (todo) => { export const getTodo = (id) => { return (dispatch) => { - return axios.get(`/api/todo/${id}`) + return axios.get(`/api/todo/${id}/`) .then(res => { dispatch(getTodo_(res.data)); }); diff --git a/src/store/reducers/todo.js b/src/store/reducers/todo.js index b34883d..113533c 100644 --- a/src/store/reducers/todo.js +++ b/src/store/reducers/todo.js @@ -15,17 +15,20 @@ const reducer = (state = initialState, action) => { switch (action.type) { case ADD_TODO: const newTodo = { - id: state.todos.length +1, - title: action.title, content:action.content, done: action.done + id: action.id, + title: action.title, + content:action.content, + done: action.done } // state.todos.push(newTodo) // BAD // state.todos.concat(newTodo) 뒤에 나오는 인자를 붙여서 새로운 리스트를 만들어준다 // 두번째 방법은 사용할 수 있다 ㅎㅎㅎㅎㅎㅎㅎㅎ - return {...state, todos: [ ...state.todos, newTodo]}; + return {...state, todos: state.todos.concat(newTodo)}; + // return {...state, todos: [ ...state.todos, newTodo]}; // action.targetID => parseInt(action.targetID) case DELETE_TODO: - const filtered = state.todos.filter(td => td.id !== action.targetID); + const filtered = state.todos.filter(td => {return td.id !== action.targetID}); return {...state, todos: filtered}; case TOGGLE_DONE: