-
-
Save yashikagarg13/bc97f0f2f9788478c0f2cd14b810cde8 to your computer and use it in GitHub Desktop.
ToDo App - Separate Action creators. source https://jsbin.com/nexumip
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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width"> | |
<title>JS Bin</title> | |
<script src="https://unpkg.com/react@15/dist/react.js"></script> | |
<script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script> | |
<script src="https://wzrd.in/standalone/deep-freeze@latest"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.3/react-redux.js"></script> | |
</head> | |
<body> | |
<div id="app"></div> | |
<script id="jsbin-javascript"> | |
// Reducers | |
const todoReducer = (state = {}, action) => { | |
switch(action.type) { | |
case "ADD_TODO": | |
return {...action.todo, completed: false}; | |
case "TOGGLE_TODO": | |
if (state.id !== action.id) { | |
return state; | |
} | |
return { | |
...state, | |
completed: !state.completed | |
} | |
default: | |
return state; | |
} | |
} | |
const todosReducer = (state = [], action) => { | |
switch(action.type) { | |
case "ADD_TODO": | |
return [...state, todoReducer(undefined, action)]; | |
case "TOGGLE_TODO": | |
return state.map(todo => todoReducer(todo, action)); | |
default: | |
return state; | |
} | |
} | |
const visbilityFilterReducer = (state = "SHOW_ALL", action) => { | |
switch(action.type) { | |
case "SET_VISIBILITY_FILTER": | |
return action.filter; | |
default: | |
return state; | |
} | |
} | |
const {combineReducers} = Redux; | |
const todoAppReducer = combineReducers({ | |
todos: todosReducer, | |
visbilityFilter: visbilityFilterReducer, | |
}); | |
// Helper Function | |
const getVisibleTodos = (todos, filter) => { | |
switch(filter) { | |
case "SHOW_ALL": | |
return todos; | |
case "SHOW_ACTIVE": | |
return todos.filter(t => !t.completed); | |
case "SHOW_COMPLETED": | |
return todos.filter(t => t.completed); | |
default: | |
return todos; | |
} | |
} | |
// Action Creators | |
let nextTodoId = 0; | |
const addTodo = (text) => { | |
return { | |
type: "ADD_TODO", | |
text, | |
id: ++nextTodoId; | |
} | |
} | |
const toggleTodo = (id) => { | |
return { | |
type: "TOGGLE_TODO", | |
id, | |
}; | |
} | |
const setVisibilityFilter = (filter) => { | |
return { | |
type: "SET_VISIBILITY_FILTER", | |
filter: filter | |
}; | |
} | |
// Components | |
const {Component} = React; | |
const {connect} = ReactRedux; | |
const Link = ({ | |
active, | |
onClick, | |
children | |
}) => { | |
return active | |
? <span>{children}</span> | |
: <a href= "#" | |
onClick={e => { | |
e.preventDefault(); | |
onClick(); | |
} | |
}> | |
{children} | |
</a> | |
}; | |
const mapStateToPropsFilterLink = (state, ownProps) => { | |
return { | |
active: ownProps.filter === state.visbilityFilter, | |
}; | |
} | |
const mapDispatchToPropsFilterLink = (dispatch, ownProps) => { | |
return { | |
onClick: () => { | |
dispatch(setVisibilityFilter(ownProps.filter)) | |
} | |
}; | |
} | |
const FilterLink = connect( | |
mapStateToPropsFilterLink, | |
mapDispatchToPropsFilterLink, | |
)(Link); | |
const Footer = () => { | |
return ( | |
<p>Show: | |
<FilterLink filter="SHOW_ALL"> | |
All</FilterLink> | |
<FilterLink filter="SHOW_ACTIVE"> | |
Active</FilterLink> | |
<FilterLink filter="SHOW_COMPLETED"> | |
Completed</FilterLink> | |
</p> | |
); | |
} | |
const ToDo = ({id, text, completed, toggleTodo}) => { | |
const completedStyle = { | |
textDecoration: "line-through", | |
}; | |
return ( | |
<li onClick={toggleTodo.bind(null, id)} | |
style={completed ? completedStyle : null }> | |
{text}</li> | |
); | |
} | |
const ToDoList = ({todos, toggleTodo}) => { | |
return ( | |
<ul> | |
{todos.map(todo => | |
<ToDo | |
key={todo.id} | |
{...todo} | |
toggleTodo={toggleTodo} /> | |
)} | |
</ul> | |
); | |
} | |
// This component is neither presentational nor container. | |
// This is kept along with behaviour because we can not break down further. | |
// SECOND param is context if we specify contextTypes. | |
let AddTodo = ({dispatch}) => { | |
let input; | |
return ( | |
<div> | |
<input type="text" ref={node => {input = node;}} /> | |
<button type="button" | |
onClick={() => { | |
dispatch(addTodo(input.value)); | |
input.value = ""; | |
}}>Submit</button> | |
</div> | |
); | |
} | |
// // SPECIFYING contextTypes IS A MUST to use context feature | |
// AddTodo.contextTypes = { | |
// store: React.PropTypes.object, | |
// }; | |
AddTodo = connect( | |
// null, // There is no need to subscribe to this store, so we are passing mapStateToProps as null | |
// null, // If we pass null or falsy value to second param, connect will pass 'dispatch' by default as prop to the component | |
// So we can go without passing any thing to conenct function | |
// if we don't want component to subscribe t store changes | |
// as well as when component only needs to access dispatch function as props. | |
)(AddTodo); | |
const mapStateToProps = (state) => { | |
return { | |
todos: getVisibleTodos(state.todos, state.visbilityFilter), | |
}; | |
} | |
const mapDispatchToProps = (dispatch) => { | |
return { | |
toggleTodo: id => { | |
dispatch(toggleTodo(id)); | |
} | |
}; | |
} | |
const VisibleTodoList = connect( | |
mapStateToProps, | |
mapDispatchToProps, | |
)(ToDoList); | |
const TodoApp = () => { | |
return ( | |
<div> | |
<AddTodo /> | |
<VisibleTodoList /> | |
<Footer /> | |
</div> | |
); | |
} | |
// class Provider extends Component { | |
// getChildContext () { | |
// return { | |
// store: this.props.store, | |
// }; | |
// } | |
// render () { | |
// return this.props.children; | |
// } | |
// } | |
// // SPECIFYING childContextTypes IS A MUST to use context feature | |
// Provider.childContextTypes = { | |
// store: React.PropTypes.object, | |
// }; | |
const {createStore} = Redux; | |
const {Provider} = ReactRedux; | |
ReactDOM.render( | |
<Provider store={createStore(todoAppReducer)}> | |
<TodoApp/> | |
</Provider>, | |
document.getElementById("app")); | |
</script> | |
<script id="jsbin-source-javascript" type="text/javascript">// Reducers | |
const todoReducer = (state = {}, action) => { | |
switch(action.type) { | |
case "ADD_TODO": | |
return {...action.todo, completed: false}; | |
case "TOGGLE_TODO": | |
if (state.id !== action.id) { | |
return state; | |
} | |
return { | |
...state, | |
completed: !state.completed | |
} | |
default: | |
return state; | |
} | |
} | |
const todosReducer = (state = [], action) => { | |
switch(action.type) { | |
case "ADD_TODO": | |
return [...state, todoReducer(undefined, action)]; | |
case "TOGGLE_TODO": | |
return state.map(todo => todoReducer(todo, action)); | |
default: | |
return state; | |
} | |
} | |
const visbilityFilterReducer = (state = "SHOW_ALL", action) => { | |
switch(action.type) { | |
case "SET_VISIBILITY_FILTER": | |
return action.filter; | |
default: | |
return state; | |
} | |
} | |
const {combineReducers} = Redux; | |
const todoAppReducer = combineReducers({ | |
todos: todosReducer, | |
visbilityFilter: visbilityFilterReducer, | |
}); | |
// Helper Function | |
const getVisibleTodos = (todos, filter) => { | |
switch(filter) { | |
case "SHOW_ALL": | |
return todos; | |
case "SHOW_ACTIVE": | |
return todos.filter(t => !t.completed); | |
case "SHOW_COMPLETED": | |
return todos.filter(t => t.completed); | |
default: | |
return todos; | |
} | |
} | |
// Action Creators | |
let nextTodoId = 0; | |
const addTodo = (text) => { | |
return { | |
type: "ADD_TODO", | |
text, | |
id: ++nextTodoId; | |
} | |
} | |
const toggleTodo = (id) => { | |
return { | |
type: "TOGGLE_TODO", | |
id, | |
}; | |
} | |
const setVisibilityFilter = (filter) => { | |
return { | |
type: "SET_VISIBILITY_FILTER", | |
filter: filter | |
}; | |
} | |
// Components | |
const {Component} = React; | |
const {connect} = ReactRedux; | |
const Link = ({ | |
active, | |
onClick, | |
children | |
}) => { | |
return active | |
? <span>{children}</span> | |
: <a href= "#" | |
onClick={e => { | |
e.preventDefault(); | |
onClick(); | |
} | |
}> | |
{children} | |
</a> | |
}; | |
const mapStateToPropsFilterLink = (state, ownProps) => { | |
return { | |
active: ownProps.filter === state.visbilityFilter, | |
}; | |
} | |
const mapDispatchToPropsFilterLink = (dispatch, ownProps) => { | |
return { | |
onClick: () => { | |
dispatch(setVisibilityFilter(ownProps.filter)) | |
} | |
}; | |
} | |
const FilterLink = connect( | |
mapStateToPropsFilterLink, | |
mapDispatchToPropsFilterLink, | |
)(Link); | |
const Footer = () => { | |
return ( | |
<p>Show: | |
<FilterLink filter="SHOW_ALL"> | |
All</FilterLink> | |
<FilterLink filter="SHOW_ACTIVE"> | |
Active</FilterLink> | |
<FilterLink filter="SHOW_COMPLETED"> | |
Completed</FilterLink> | |
</p> | |
); | |
} | |
const ToDo = ({id, text, completed, toggleTodo}) => { | |
const completedStyle = { | |
textDecoration: "line-through", | |
}; | |
return ( | |
<li onClick={toggleTodo.bind(null, id)} | |
style={completed ? completedStyle : null }> | |
{text}</li> | |
); | |
} | |
const ToDoList = ({todos, toggleTodo}) => { | |
return ( | |
<ul> | |
{todos.map(todo => | |
<ToDo | |
key={todo.id} | |
{...todo} | |
toggleTodo={toggleTodo} /> | |
)} | |
</ul> | |
); | |
} | |
// This component is neither presentational nor container. | |
// This is kept along with behaviour because we can not break down further. | |
// SECOND param is context if we specify contextTypes. | |
let AddTodo = ({dispatch}) => { | |
let input; | |
return ( | |
<div> | |
<input type="text" ref={node => {input = node;}} /> | |
<button type="button" | |
onClick={() => { | |
dispatch(addTodo(input.value)); | |
input.value = ""; | |
}}>Submit</button> | |
</div> | |
); | |
} | |
// // SPECIFYING contextTypes IS A MUST to use context feature | |
// AddTodo.contextTypes = { | |
// store: React.PropTypes.object, | |
// }; | |
AddTodo = connect( | |
// null, // There is no need to subscribe to this store, so we are passing mapStateToProps as null | |
// null, // If we pass null or falsy value to second param, connect will pass 'dispatch' by default as prop to the component | |
// So we can go without passing any thing to conenct function | |
// if we don't want component to subscribe t store changes | |
// as well as when component only needs to access dispatch function as props. | |
)(AddTodo); | |
const mapStateToProps = (state) => { | |
return { | |
todos: getVisibleTodos(state.todos, state.visbilityFilter), | |
}; | |
} | |
const mapDispatchToProps = (dispatch) => { | |
return { | |
toggleTodo: id => { | |
dispatch(toggleTodo(id)); | |
} | |
}; | |
} | |
const VisibleTodoList = connect( | |
mapStateToProps, | |
mapDispatchToProps, | |
)(ToDoList); | |
const TodoApp = () => { | |
return ( | |
<div> | |
<AddTodo /> | |
<VisibleTodoList /> | |
<Footer /> | |
</div> | |
); | |
} | |
// class Provider extends Component { | |
// getChildContext () { | |
// return { | |
// store: this.props.store, | |
// }; | |
// } | |
// render () { | |
// return this.props.children; | |
// } | |
// } | |
// // SPECIFYING childContextTypes IS A MUST to use context feature | |
// Provider.childContextTypes = { | |
// store: React.PropTypes.object, | |
// }; | |
const {createStore} = Redux; | |
const {Provider} = ReactRedux; | |
ReactDOM.render( | |
<Provider store={createStore(todoAppReducer)}> | |
<TodoApp/> | |
</Provider>, | |
document.getElementById("app")); | |
</script></body> | |
</html> |
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
// Reducers | |
const todoReducer = (state = {}, action) => { | |
switch(action.type) { | |
case "ADD_TODO": | |
return {...action.todo, completed: false}; | |
case "TOGGLE_TODO": | |
if (state.id !== action.id) { | |
return state; | |
} | |
return { | |
...state, | |
completed: !state.completed | |
} | |
default: | |
return state; | |
} | |
} | |
const todosReducer = (state = [], action) => { | |
switch(action.type) { | |
case "ADD_TODO": | |
return [...state, todoReducer(undefined, action)]; | |
case "TOGGLE_TODO": | |
return state.map(todo => todoReducer(todo, action)); | |
default: | |
return state; | |
} | |
} | |
const visbilityFilterReducer = (state = "SHOW_ALL", action) => { | |
switch(action.type) { | |
case "SET_VISIBILITY_FILTER": | |
return action.filter; | |
default: | |
return state; | |
} | |
} | |
const {combineReducers} = Redux; | |
const todoAppReducer = combineReducers({ | |
todos: todosReducer, | |
visbilityFilter: visbilityFilterReducer, | |
}); | |
// Helper Function | |
const getVisibleTodos = (todos, filter) => { | |
switch(filter) { | |
case "SHOW_ALL": | |
return todos; | |
case "SHOW_ACTIVE": | |
return todos.filter(t => !t.completed); | |
case "SHOW_COMPLETED": | |
return todos.filter(t => t.completed); | |
default: | |
return todos; | |
} | |
} | |
// Action Creators | |
let nextTodoId = 0; | |
const addTodo = (text) => { | |
return { | |
type: "ADD_TODO", | |
text, | |
id: ++nextTodoId; | |
} | |
} | |
const toggleTodo = (id) => { | |
return { | |
type: "TOGGLE_TODO", | |
id, | |
}; | |
} | |
const setVisibilityFilter = (filter) => { | |
return { | |
type: "SET_VISIBILITY_FILTER", | |
filter: filter | |
}; | |
} | |
// Components | |
const {Component} = React; | |
const {connect} = ReactRedux; | |
const Link = ({ | |
active, | |
onClick, | |
children | |
}) => { | |
return active | |
? <span>{children}</span> | |
: <a href= "#" | |
onClick={e => { | |
e.preventDefault(); | |
onClick(); | |
} | |
}> | |
{children} | |
</a> | |
}; | |
const mapStateToPropsFilterLink = (state, ownProps) => { | |
return { | |
active: ownProps.filter === state.visbilityFilter, | |
}; | |
} | |
const mapDispatchToPropsFilterLink = (dispatch, ownProps) => { | |
return { | |
onClick: () => { | |
dispatch(setVisibilityFilter(ownProps.filter)) | |
} | |
}; | |
} | |
const FilterLink = connect( | |
mapStateToPropsFilterLink, | |
mapDispatchToPropsFilterLink, | |
)(Link); | |
const Footer = () => { | |
return ( | |
<p>Show: | |
<FilterLink filter="SHOW_ALL"> | |
All</FilterLink> | |
<FilterLink filter="SHOW_ACTIVE"> | |
Active</FilterLink> | |
<FilterLink filter="SHOW_COMPLETED"> | |
Completed</FilterLink> | |
</p> | |
); | |
} | |
const ToDo = ({id, text, completed, toggleTodo}) => { | |
const completedStyle = { | |
textDecoration: "line-through", | |
}; | |
return ( | |
<li onClick={toggleTodo.bind(null, id)} | |
style={completed ? completedStyle : null }> | |
{text}</li> | |
); | |
} | |
const ToDoList = ({todos, toggleTodo}) => { | |
return ( | |
<ul> | |
{todos.map(todo => | |
<ToDo | |
key={todo.id} | |
{...todo} | |
toggleTodo={toggleTodo} /> | |
)} | |
</ul> | |
); | |
} | |
// This component is neither presentational nor container. | |
// This is kept along with behaviour because we can not break down further. | |
// SECOND param is context if we specify contextTypes. | |
let AddTodo = ({dispatch}) => { | |
let input; | |
return ( | |
<div> | |
<input type="text" ref={node => {input = node;}} /> | |
<button type="button" | |
onClick={() => { | |
dispatch(addTodo(input.value)); | |
input.value = ""; | |
}}>Submit</button> | |
</div> | |
); | |
} | |
// // SPECIFYING contextTypes IS A MUST to use context feature | |
// AddTodo.contextTypes = { | |
// store: React.PropTypes.object, | |
// }; | |
AddTodo = connect( | |
// null, // There is no need to subscribe to this store, so we are passing mapStateToProps as null | |
// null, // If we pass null or falsy value to second param, connect will pass 'dispatch' by default as prop to the component | |
// So we can go without passing any thing to conenct function | |
// if we don't want component to subscribe t store changes | |
// as well as when component only needs to access dispatch function as props. | |
)(AddTodo); | |
const mapStateToProps = (state) => { | |
return { | |
todos: getVisibleTodos(state.todos, state.visbilityFilter), | |
}; | |
} | |
const mapDispatchToProps = (dispatch) => { | |
return { | |
toggleTodo: id => { | |
dispatch(toggleTodo(id)); | |
} | |
}; | |
} | |
const VisibleTodoList = connect( | |
mapStateToProps, | |
mapDispatchToProps, | |
)(ToDoList); | |
const TodoApp = () => { | |
return ( | |
<div> | |
<AddTodo /> | |
<VisibleTodoList /> | |
<Footer /> | |
</div> | |
); | |
} | |
// class Provider extends Component { | |
// getChildContext () { | |
// return { | |
// store: this.props.store, | |
// }; | |
// } | |
// render () { | |
// return this.props.children; | |
// } | |
// } | |
// // SPECIFYING childContextTypes IS A MUST to use context feature | |
// Provider.childContextTypes = { | |
// store: React.PropTypes.object, | |
// }; | |
const {createStore} = Redux; | |
const {Provider} = ReactRedux; | |
ReactDOM.render( | |
<Provider store={createStore(todoAppReducer)}> | |
<TodoApp/> | |
</Provider>, | |
document.getElementById("app")); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment