Last active
August 23, 2019 19:14
-
-
Save park-brian/ea5e27f9ba18dfb38afc7ece24858e95 to your computer and use it in GitHub Desktop.
React Redux ES5 - TodoMVC
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 lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>GistRun</title> | |
<!-- React/ReactDOM --> | |
<script src="https://cdn.jsdelivr.net/combine/npm/react@16.8.6/umd/react.production.min.js,npm/react-dom@16.8.6/umd/react-dom.production.min.js"></script> | |
<!-- Redux/Redux Thunk/React Redux --> | |
<script src="https://cdn.jsdelivr.net/combine/npm/redux@4.0.4/dist/redux.min.js,npm/redux-thunk@2.3.0/dist/redux-thunk.min.js,npm/react-redux@7.1.0/dist/react-redux.min.js"></script> | |
<link rel="stylesheet" href="styles.css"> | |
</head> | |
<body> | |
<main id="root" class="container">Loading...</main> | |
<script src="script.js"></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
var c = React.createElement; | |
// create a redux store using a reducer and an initial state | |
var initialState = { | |
todos: [], | |
newTodo: {id: null, text: '', complete: false}, | |
} | |
// include redux-thunk and devtools | |
var middleware = Redux.compose( | |
ReduxThunk.default, | |
__REDUX_DEVTOOLS_EXTENSION__ && __REDUX_DEVTOOLS_EXTENSION__() | |
); | |
// create store | |
var store = Redux.createStore( | |
reducer, | |
initialState, | |
Redux.applyMiddleware(middleware) | |
); | |
// create todos reducer | |
function reducer(state, action) { | |
switch(action.type) { | |
case 'UPDATE_NEW_TODO': | |
return Object.assign({}, state, { | |
newTodo: action.item, | |
}); | |
case 'ADD_TODO': | |
return Object.assign({}, state, { | |
todos: state.todos.concat( | |
Object.assign({}, action.item, { | |
id: Math.random() | |
}) | |
) | |
}); | |
case 'REMOVE_TODO': | |
return Object.assign({}, state, { | |
todos: state.todos.filter(function(item) { | |
return item.id !== action.item.id; | |
}) | |
}); | |
case 'UPDATE_TODO': | |
return Object.assign({}, state, { | |
todos: state.todos.map(function(item) { | |
if (item.id === action.item.id) | |
return Object.assign({}, item, action.item) | |
return item; | |
}) | |
}); | |
default: | |
return state; | |
} | |
}; | |
// define action creators | |
var actions = Redux.bindActionCreators({ | |
updateNewTodo: function(item) { | |
return {type: 'UPDATE_NEW_TODO', item, item} | |
}, | |
addTodo: function(item) { | |
return {type: 'ADD_TODO', item: item}; | |
}, | |
removeTodo: function(item) { | |
return {type: 'REMOVE_TODO', item: item}; | |
}, | |
updateTodo: function(item) { | |
return {type: 'UPDATE_TODO', item: item}; | |
}, | |
}, store.dispatch); | |
// create a presentational Counter component | |
function TodoItems(props) { | |
var todos = ReactRedux.useSelector(function(state) { | |
return state.todos; | |
}); | |
return c(React.Fragment, null, todos.map(function(item) { | |
return c('div', { | |
className: 'flex w-100 mb-1 align-items-center', | |
}, [ | |
c('input', { | |
className: 'input w-90', | |
value: item.text, | |
onChange: function(event) { | |
var value = event.target.value; | |
actions.updateTodo({ | |
id: item.id, | |
text: value, | |
}); | |
} | |
}), | |
c('button', { | |
className: 'button bg-secondary w-10', | |
onClick: function(event) { | |
actions.removeTodo(item) | |
} | |
}, 'x'), | |
]); | |
})); | |
} | |
function NewTodoItem(props) { | |
var newTodo = ReactRedux.useSelector(function(state) { | |
return state.newTodo; | |
}); | |
return c('form', { | |
className: 'flex w-100 mb-1', | |
onSubmit: function(event) { | |
event.preventDefault(); | |
if (!newTodo.text) return; | |
actions.addTodo(newTodo); | |
actions.updateNewTodo({ text: '' }); | |
} | |
}, [ | |
c('input', { | |
'aria-label': 'Enter a todo', | |
className: 'input w-90', | |
value: newTodo.text, | |
placeholder: 'Enter a todo item', | |
onChange: function(event) { | |
var value = event.target.value; | |
actions.updateNewTodo({ text: value }); | |
} | |
}), | |
c('button', { | |
type: 'submit', | |
className: 'button bg-primary w-10', | |
}, '+') | |
]) | |
} | |
function TodoApp(props) { | |
return c(React.Fragment, null, [ | |
c('h1', null, 'Todos'), | |
c(NewTodoItem), | |
c('hr', {className: 'my-2'}), | |
c(TodoItems) | |
]); | |
} | |
// provide store to the root component | |
function App() { | |
return c( | |
ReactRedux.Provider, | |
{store: store}, | |
c(TodoApp) | |
); | |
} | |
// render app | |
ReactDOM.render(App(), document.querySelector('#root')); |
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
* { | |
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; | |
box-sizing: border-box; | |
} | |
hr { | |
border: none; | |
border-bottom: 1px solid #eee; | |
} | |
.w-10 { width: 10%; } | |
.w-20 { width: 20%; } | |
.w-30 { width: 30%; } | |
.w-40 { width: 40%; } | |
.w-50 { width: 50%; } | |
.w-60 { width: 60%; } | |
.w-70 { width: 70%; } | |
.w-80 { width: 80%; } | |
.w-90 { width: 90%; } | |
.w-100 { width: 100%; } | |
.m-0 { margin: 0; } | |
.p-0 { padding: 0; } | |
.my-2 { margin-top: 1rem; margin-bottom: 1rem; } | |
.mb-1 { margin-bottom: 0.5rem; } | |
.container { | |
min-width: 200px; | |
width: 400px; | |
max-width: 800px; | |
margin: 0 auto; | |
} | |
.flex { | |
display: flex; | |
} | |
.align-items-center { | |
align-items: center; | |
} | |
.align-items-stretch { | |
align-items: stretch; | |
} | |
.input, .button { | |
border: 1px solid #ddd; | |
} | |
.input + .button { | |
border-left: none; | |
} | |
.input { | |
padding: 0.5rem; | |
} | |
.button { | |
padding: 0.5rem 0.75rem; | |
cursor: pointer; | |
} | |
.bg-primary { | |
color: white; | |
background-color: steelblue; | |
border-color: steelblue; | |
} | |
.bg-secondary { | |
color: #444; | |
background-color: #eee; | |
border-color: #ddd; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment