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"))