React
HTML
<div id="app"></div>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
.done {
color: rgba(0, 0, 0, 0.3);
text-decoration: line-through;
}
input {
margin-right: 5px;
}
React
function useMappedState(defaultState = {}) {
const keys = Object.keys(defaultState);
return keys.reduce((map, k) => {
const fk = `set${k.charAt(0).toUpperCase()}${k.slice(1)}`;
const [state, setState] = React.useState(defaultState[k]);
map[k] = state;
map[fk] = setState;
return map;
}, {});
}
function TodoApp() {
const state = useMappedState({
todoCount: 100,
doneCount: 0
});
const addTodo = React.useCallback(() => {
state.setTodoCount(state.todoCount + 1);
}, [state.todoCount]);
const completeTodo = React.useCallback(() => {
state.setDoneCount(state.doneCount + 1);
}, [state.doneCount]);
console.log(state);
console.log('Rendering...');
return (
<div>
<ul>
<li>Todo Count: {state.todoCount}</li>
<li>Done Count: {state.doneCount}</li>
</ul>
<button onClick={addTodo}>Add Todo</button>
<button onClick={completeTodo}>Complete Todo</button>
</div>
);
}
ReactDOM.render(<TodoApp />, document.querySelector("#app"))