Created
April 26, 2017 22:55
-
-
Save KDCinfo/7480e74adbc7fa3c4947dd605c81a4f3 to your computer and use it in GitHub Desktop.
Redux Docs - Todo App - Streamlined into One File
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The following code was extracted from the Redux docs and streamlined into one file | |
// I only did this to get a simplistic skeleton, so I could see how they all fit together | |
// ...and just to see that they all could work from one file :) | |
// http://redux.js.org/docs/basics/ExampleTodoList.html | |
// [npm: v3.6.0, changelog: #187] | |
// // // // // // // // // // | |
// Entry Point | |
// // // // // // // // // // | |
// index.js | |
// // // // // // // // // // | |
import React, { PropTypes } from 'react' | |
import { render } from 'react-dom' | |
import { Provider, connect } from 'react-redux' | |
import { createStore, combineReducers } from 'redux' | |
// import todoApp from './reducers' | |
// import App from './components/App' | |
// // // // // // // // // // | |
// Action Creators | |
// // // // // // // // // // | |
// actions/index.js | |
// // // // // // // // // // | |
let nextTodoId = 0 | |
const addTodo = (text) => { | |
return { | |
type: 'ADD_TODO', | |
id: nextTodoId++, | |
text | |
} | |
} | |
const setVisibilityFilter = (filter) => { | |
return { | |
type: 'SET_VISIBILITY_FILTER', | |
filter | |
} | |
} | |
const toggleTodo = (id) => { | |
return { | |
type: 'TOGGLE_TODO', | |
id | |
} | |
} | |
// // // // // // // // // // | |
// Reducers | |
// // // // // // // // // // | |
// reducers/todos.js | |
// // // // // // // // // // | |
const todo = (state = {}, action) => { | |
switch (action.type) { | |
case 'ADD_TODO': | |
return { | |
id: action.id, | |
text: action.text, | |
completed: false | |
} | |
case 'TOGGLE_TODO': | |
if (state.id !== action.id) { | |
return state | |
} | |
return Object.assign({}, state, { | |
completed: !state.completed | |
}) | |
default: | |
return state | |
} | |
} | |
const todos = (state = [], action) => { | |
switch (action.type) { | |
case 'ADD_TODO': | |
return [ | |
...state, | |
todo(undefined, action) | |
] | |
case 'TOGGLE_TODO': | |
return state.map(t => | |
todo(t, action) | |
) | |
default: | |
return state | |
} | |
} | |
// // // // // // // // // // | |
// reducers/visibilityFilter.js | |
const visibilityFilter = (state = 'SHOW_ALL', action) => { | |
switch (action.type) { | |
case 'SET_VISIBILITY_FILTER': | |
return action.filter | |
default: | |
return state | |
} | |
} | |
// // // // // // // // // // | |
// reducers/index.js | |
// import todos from './todos' | |
// import visibilityFilter from './visibilityFilter' | |
const todoApp = combineReducers({ | |
todos, | |
visibilityFilter | |
}) | |
// // // // // // // // // // | |
// Presentational Components | |
// // // // // // // // // // | |
// components/Todo.js | |
// // // // // // // // // // | |
const Todo = ({ onClick, completed, text }) => ( | |
<li | |
onClick={onClick} | |
style={{ | |
textDecoration: completed ? 'line-through' : 'none' | |
}} | |
> | |
{text} | |
</li> | |
) | |
Todo.propTypes = { | |
onClick: PropTypes.func.isRequired, | |
completed: PropTypes.bool.isRequired, | |
text: PropTypes.string.isRequired | |
} | |
// // // // // // // // // // | |
// components/TodoList.js | |
// import Todo from './Todo' | |
const TodoList = ({ todos, onTodoClick }) => ( | |
<ul> | |
{todos.map(todo => | |
<Todo | |
key={todo.id} | |
{...todo} | |
onClick={() => onTodoClick(todo.id)} | |
/> | |
)} | |
</ul> | |
) | |
TodoList.propTypes = { | |
todos: PropTypes.arrayOf(PropTypes.shape({ | |
id: PropTypes.number.isRequired, | |
completed: PropTypes.bool.isRequired, | |
text: PropTypes.string.isRequired | |
}).isRequired).isRequired, | |
onTodoClick: PropTypes.func.isRequired | |
} | |
// // // // // // // // // // | |
// components/Link.js | |
const Link = ({ active, children, onClick }) => { | |
if (active) { | |
return <span>{children}</span> | |
} | |
return ( | |
<a href="#" | |
onClick={e => { | |
e.preventDefault() | |
onClick() | |
}} | |
> | |
{children} | |
</a> | |
) | |
} | |
Link.propTypes = { | |
active: PropTypes.bool.isRequired, | |
children: PropTypes.node.isRequired, | |
onClick: PropTypes.func.isRequired | |
} | |
// // // // // // // // // // | |
// components/Footer.js | |
// import FilterLink from '../containers/FilterLink' | |
const Footer = () => ( | |
<p> | |
Show: | |
{" "} | |
<FilterLink filter="SHOW_ALL"> | |
All | |
</FilterLink> | |
{", "} | |
<FilterLink filter="SHOW_ACTIVE"> | |
Active | |
</FilterLink> | |
{", "} | |
<FilterLink filter="SHOW_COMPLETED"> | |
Completed | |
</FilterLink> | |
</p> | |
) | |
// // // // // // // // // // | |
// components/App.js | |
// import Footer from './Footer' | |
// import AddTodo from '../containers/AddTodo' | |
// import VisibleTodoList from '../containers/VisibleTodoList' | |
const App = () => ( | |
<div> | |
<AddTodo /> | |
<VisibleTodoList /> | |
<Footer /> | |
</div> | |
) | |
// // // // // // // // // // | |
// Container Components | |
// // // // // // // // // // | |
// containers/VisibleTodoList.js | |
// // // // // // // // // // | |
// import { toggleTodo } from '../actions' | |
// import TodoList from '../components/TodoList' | |
const getVisibleTodos = (todos, filter) => { | |
switch (filter) { | |
case 'SHOW_ALL': | |
return todos | |
case 'SHOW_COMPLETED': | |
return todos.filter(t => t.completed) | |
case 'SHOW_ACTIVE': | |
return todos.filter(t => !t.completed) | |
} | |
} | |
let mapStateToProps | |
let mapDispatchToProps | |
mapStateToProps = (state) => { | |
return { | |
todos: getVisibleTodos(state.todos, state.visibilityFilter) | |
} | |
} | |
mapDispatchToProps = (dispatch) => { | |
return { | |
onTodoClick: (id) => { | |
dispatch(toggleTodo(id)) | |
} | |
} | |
} | |
const VisibleTodoList = connect( | |
mapStateToProps, | |
mapDispatchToProps | |
)(TodoList) | |
// // // // // // // // // // | |
// containers/FilterLink.js | |
// import { setVisibilityFilter } from '../actions' | |
// import Link from '../components/Link' | |
mapStateToProps = (state, ownProps) => { | |
return { | |
active: ownProps.filter === state.visibilityFilter | |
} | |
} | |
mapDispatchToProps = (dispatch, ownProps) => { | |
return { | |
onClick: () => { | |
dispatch(setVisibilityFilter(ownProps.filter)) | |
} | |
} | |
} | |
const FilterLink = connect( | |
mapStateToProps, | |
mapDispatchToProps | |
)(Link) | |
// // // // // // // // // // | |
// Other Components | |
// // // // // // // // // // | |
// containers/AddTodo.js | |
// // // // // // // // // // | |
// import { addTodo } from '../actions' | |
let AddTodo = ({ dispatch }) => { | |
let input | |
return ( | |
<div> | |
<form onSubmit={e => { | |
e.preventDefault() | |
if (!input.value.trim()) { | |
return | |
} | |
dispatch(addTodo(input.value)) | |
input.value = '' | |
}}> | |
<input ref={node => { | |
input = node | |
}} /> | |
<button type="submit"> | |
Add Todo | |
</button> | |
</form> | |
</div> | |
) | |
} | |
AddTodo = connect()(AddTodo) | |
let store = createStore(todoApp) | |
render( | |
<Provider store={store}> | |
<App /> | |
</Provider>, | |
document.getElementById('app') | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment