Last active
November 10, 2016 06:56
-
-
Save finalfantasia/b3c9f29387f0634288fdb6d5d6eb57e7 to your computer and use it in GitHub Desktop.
React-Redux Todo App
This file contains hidden or 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
// <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.js"></script> | |
// <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.js"></script> | |
/* | |
<body> | |
<div id="root" /> | |
</body> | |
*/ | |
// redux api | |
const combineReducers = reducers => | |
(state = {}, action) => | |
Object.keys (reducers). | |
reduce ( | |
(accumulator, key) => | |
Object.assign ({}, accumulator, {[key]: reducers [key] (state [key], action)}), | |
{}) | |
const createStore = reducer => { | |
let state | |
let listeners = [] | |
const getState = () => state | |
const subscribe = listener => { | |
listeners.push (listener) | |
const unsubscribe = () => listeners = listeners.filter (l => l !== listener) | |
return unsubscribe | |
} | |
const dispatch = action => { | |
state = reducer (state, action) | |
listeners.forEach (listener => listener ()) | |
} | |
dispatch ({}) | |
return { | |
getState, | |
subscribe, | |
dispatch | |
} | |
} | |
// redux reducers | |
const todo = (state = {}, {type, id, text}) => { | |
switch (type) { | |
case 'ADD_TODO': return { | |
id: id, | |
text: text, | |
done: false | |
} | |
case 'TOGGLE_TODO': | |
return Object.assign ({}, state, {done: !state.done}) | |
default: return state | |
} | |
} | |
const todos = (state = [], action) => { | |
const {type, id, text} = action | |
switch (type) { | |
case 'ADD_TODO': return [ | |
...state, | |
todo ({}, action) | |
] | |
case 'TOGGLE_TODO': | |
return state.map (t => t.id === id ? todo (t, {type: type}) : t) | |
default: return state | |
} | |
} | |
const visibility = (state = '', {type, visibility}) => { | |
switch (type) { | |
case 'SET_VISIBILITY': return visibility | |
default: return state | |
} | |
} | |
const nextId = (state = 0, {type}) => { | |
switch (type) { | |
case 'INCREMENT_ID': return state + 1 | |
default: return state | |
} | |
} | |
const todoApp = combineReducers ({todos, nextId, visibility}) | |
// react components | |
const Filter = ({store, visibility, children}) => ( | |
<button disabled={store.getState ().visibility === visibility} | |
onClick={event => { | |
store.dispatch ({ | |
type: 'SET_VISIBILITY', | |
visibility | |
}) | |
}}> | |
{children} | |
</button> | |
) | |
const TodoApp = ({store}) => { | |
const todoFilter = visibility => todo => { | |
switch (visibility) { | |
case 'DONE_ONLY': return todo.done | |
case 'NOT_DONE_ONLY': return !todo.done | |
case 'ALL': return true | |
default: return true | |
} | |
} | |
let input | |
return ( | |
<div> | |
<input ref={node => input = node} /> | |
<button onClick={() => { | |
store.dispatch ({type: 'ADD_TODO', text: input.value, id: store.getState ().nextId}) | |
store.dispatch ({type: 'INCREMENT_ID'}) | |
input.value = ''}}> | |
Add | |
</button> | |
<p> | |
Show: | |
<Filter store={store} visibility='ALL'>All</Filter> | |
<Filter store={store} visibility='DONE_ONLY'>Done</Filter> | |
<Filter store={store} visibility='NOT_DONE_ONLY'>Not Done</Filter> | |
</p> | |
<ul> | |
{store.getState ().todos.filter (todoFilter (store.getState ().visibility)).map (todo => | |
<li key={todo.id} onClick={() => store.dispatch ({type: 'TOGGLE_TODO', id: todo.id})}> | |
{todo.done ? '🏁' : '🏳️'} {todo.text} | |
</li> | |
)} | |
</ul> | |
</div> | |
) | |
} | |
// app | |
const store = createStore (todoApp) | |
const render = () => ReactDOM.render ( | |
<TodoApp store={store}/>, | |
document.querySelector ('#root') | |
) | |
store.subscribe (render) | |
render () |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment