Uso de React.Children y React.cloneElement

Usaremos estas funcionalidades de React para pasar un atributo (loading) desde el padre TodoHeader a todos sus hijos (TodoCounter y TodoSearch).

function App() {
	...
  return (
    <React.Fragment>
      <TodoHeader loading={loading}>
        <TodoCounter totalTodos={totalTodos} completedTodos={completedTodos} />
        <TodoSearch searchValue={searchValue} setSearchValue={setSearchValue} />
      </TodoHeader>
			...
    </React.Fragment>
  );
}
function TodoHeader({ children, loading }) {
  return (
    <header>
      {React.Children.toArray(children).map((child) =>
        React.cloneElement(child, { loading })
      )}
    </header>
  );
}

Opacidad al cargar la App

Agregamos estilos para que los componentes tengan tono de deshabilitado mientras cargan, usando el atributo loading que se pasó anteriormente.

function TodoCounter({ totalTodos, completedTodos, loading }) {
  return (
    <h2 className={`TodoCounter ${!!loading && "TodoCounter--loading"}`}>
      Has completado {completedTodos} de {totalTodos} TODOs
    </h2>
  );
}
.TodoCounter--loading {
  opacity: 25%;
}
function TodoSearch({ searchValue, setSearchValue, loading }) {
  const onSearchValueChange = (event) => {
    console.log(event.target.value);
    setSearchValue(event.target.value);
  };

  return (
    <input
      className="TodoSearch"
      placeholder="Cebolla"
      value={searchValue}
      onChange={onSearchValueChange}
      disabled={loading}
    />
  );
}
.TodoSearch:disabled {
  opacity: 25%;
}

Archivos de la Clase

React.Children y React.cloneElement

https://github.com/FROSTYLAN/TodoApp/commit/ccd5964ec0bf30a6b06ac6d7188ce4bab1546467