Fala Denis, tudo bem ?
Uma questão chave que devemos sempre pensar é na reutilização dos recursos. Portanto, poderíamos nos perguntar: "Os componentes Rodape, FormLogin, FormContato serão realmente reutilizados em outros pontos da aplicação?". Se a resposta é sim, podemos com certeza fazer a divisão em componentes menores. Com o cuidado é claro de não fazer divisões desnecessárias, por exemplo, o conteúdo de FormLogin, precisa mesmo estar separado do login.js? Ele vai ser usado fora dele? Se não vai, poderia ficar no próprio arquivo. Tente sempre focar na questão da manutenção do estado (as informações que cada um mantém) dos componentes.
Um exemplo do que eu faria diante de algumas premissas:
- Premissa 1: Rodapé será reutilizado em vários outros componentes (páginas) (como é muito comum)
Neste caso criaria o componente Rodape.js, contendo toda sua marcação visual e estado necessários.
- Premissa 2: Form de login só vai ser usado dentro da página de login (componente Login.js)
Neste caso deixaria a marcação do form e estado necessário para armazenar os dados que o usuário digite dentro do próprio Login.js, evitando fazer quebras desnecessárias.
OBS: Uma exceção que uso para essa questão/regra de quebrar apenas quando vou reutilizar é verificar se o código não fica grande/complexo demais, concentrando mais de uma responsabilidade no Login.js. Por exemplo, se você tiver que manter no estado do componente, além do estado dos campos de texto (algo simples), mas também precisar manter algum outro estado mais complexo para o componente e sua regra de negócio. Aí é legal avaliar uma possível divisão.
- Premissa 3: FormContato vai ser utilizado na página/componente de login e em alguma outra página da aplicação (uma possível Contato.js, por exemplo)
Neste caso criaria o FormContato, apenas com a marcação e o estado deste formulário, reutilizando este componente em Login.js, Contato.js e qualquer outro componente onde seja necessário.
Sobre a divisão entre componente e lógica de negocio inerente (seu exemplo sobre a validação) é importante tomar outro cuidado. A ideia do react na divisão dos componentes é formada em cima do paradigma de Orientação a Objetos que preza sempre pela manutenção de estado e comportamento desse modelo (ou componente nesse caso). Nesse caso pense sempre numa extração dos dois, visando reaproveitamento. Separar estado das funcionalidades leva a solução para uma pegada mais procedural e pode trazer problemas. Eu tentaria criar um UsuarioValidator.js que tenha os dados e validações (nao apenas as validações) de negócio necessários e reaproveitar nos pontos onde seja necessário. Nesse caso qualquer que seja o form onde venha uma informação do usuário, você poderia fazer algo assim:
// onde usuario é um objeto literal (por exemplo) com dados vindos do form de login, ou qualquer outro
const validator = new UsuarioValidator(usuario); // objeto validador recebe os dados e mantem internamente
if (validator.temUsuarioValido()) { // método temUsuarioValido testa o que for necessário para comprovar que os dados do usuario (no estado do validador) estão dentro do esperado para o caso
// segue o jogo, tudo certo com os dados
}
Enfim acho que consegui mostrar um pouco das preocupações que tenho ao escrever/dividir componentes. Existem inúmeras outras técnicas, práticas e etc que podem seu usadas para facilitar o trabalho. Eu sempre tento pensar em algumas: Pensar sempre em favorecer a interface do componente (como ele vai ser utilizado por outros modulos) do que em sua implementação, que vem em consequencia disso; Pensar sempre em manter uma única responsabilidade no componente, para facilitar sua manutenção e evolução, etc etc. Sempre recomendo o estudo de práticas e recomendações de OO, que vai te ajudar nesse sentido.
Espero ter ajudado no pensamento. Abraço!