Apresentamos a sua atenção a tradução de um artigo de Scott Domes, publicado no blog.bitsrc.io. Descubra no kat por que os componentes devem ser tão pequenos quanto possível e como o princípio da responsabilidade exclusiva afeta a qualidade das aplicações.

Foto
Austin Kirk com
UnsplashA vantagem do sistema de componentes React (e bibliotecas semelhantes) é que sua interface do usuário é dividida em pequenas partes que são fáceis de ler e reutilizáveis.
Esses componentes são compactos (100-200 linhas), o que permite que outros desenvolvedores os entendam e modifiquem facilmente.
Embora os componentes, em regra, tentem ser mais curtos, não há uma restrição clara e estrita no seu comprimento. O React não se importará se você decidir encaixar seu aplicativo em um componente assustadoramente grande, composto por 3.000 linhas.
... mas não vale a pena. A maioria dos seus componentes, provavelmente, já é muito volumosa - ou melhor, eles executam muitas funções.
Neste artigo, vou provar que a maioria dos componentes (mesmo com o comprimento normal de 200 linhas) deve ter um alvo mais restrito. Eles devem executar apenas uma função e executá-la bem. É isso que Eddie Osmani diz muito bem
aqui .
Dica : ao trabalhar em JS,
use Bit para organizar, montar e reutilizar componentes como peças lego. Bit é uma ferramenta extremamente eficaz para esse negócio, ele ajudará você e sua equipe a economizar tempo e acelerar a montagem. Apenas tente.
Vamos demonstrar como, ao criar componentes
, algo pode dar errado .
Nosso aplicativo
Imagine que temos um aplicativo padrão para blogueiros. E aqui está o que na tela principal:
class Main extends React.Component { render() { return ( <div> <header> // Header JSX </header> <aside id="header"> // Sidebar JSX </aside> <div id="post-container"> {this.state.posts.map(post => { return ( <div className="post"> // Post JSX </div> ); })} </div> </div> ); } }
(Este exemplo, como muitos outros subsequentes, deve ser considerado como pseudocódigo.)Ele exibe o painel superior, a barra lateral e a lista de postagens. Tudo é simples.
Como também precisamos baixar postagens, podemos fazer isso enquanto o componente está sendo montado:
class Main extends React.Component { state = { posts: [] }; componentDidMount() { this.loadPosts(); } loadPosts() {
Também temos alguma lógica pela qual a barra lateral é chamada. Se o usuário clicar no botão no painel superior, o lado será fechado. Você pode fechá-lo de cima e do próprio painel lateral.
class Main extends React.Component { state = { posts: [], isSidebarOpen: false }; componentDidMount() { this.loadPosts(); } loadPosts() {
Nosso componente se tornou um pouco mais complicado, mas ainda fácil de ler.
Pode-se argumentar que todas as suas partes servem a um propósito: exibir a página principal do aplicativo. Então, seguimos o princípio da responsabilidade exclusiva.
O princípio da responsabilidade exclusiva afirma que um componente deve cumprir apenas uma função. Se reformularmos a definição retirada de
wikipedia.org , verifica-se que cada componente deve ser responsável por apenas uma parte da funcionalidade [aplicativo].
Nosso componente principal atende a esse requisito. Qual é o problema?
Aqui está uma formulação diferente do princípio:
qualquer [componente] deve ter apenas um motivo para a mudança .
Esta definição é retirada do
livro de Robert Martin
, Rapid Software Development. Princípios, exemplos, prática ” e é de grande importância.
Ao focar em
um motivo para alterar nossos componentes, podemos criar aplicativos melhores que, além disso, serão fáceis de configurar.
Para maior clareza, vamos complicar nosso componente.
Complicação
Suponha que um mês após a implementação do componente Principal, um novo recurso tenha sido atribuído ao desenvolvedor por nossa equipe. Agora, o usuário poderá ocultar uma postagem (por exemplo, se ela contiver conteúdo inapropriado).
Isso não é difícil de fazer!
class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [] };
Nosso colega lidou facilmente com isso. Ela adicionou apenas um novo método e uma nova propriedade. Nenhum dos que examinou a pequena lista de mudanças teve objeções.
Algumas semanas depois, outro recurso é anunciado - uma barra lateral aprimorada para a versão móvel. Em vez de mexer com CSS, o desenvolvedor decide criar vários componentes JSX que serão executados apenas em dispositivos móveis.
class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [], isMobileSidebarOpen: false };
Outra pequena mudança. Alguns novos métodos bem nomeados e uma nova propriedade.
E aqui temos um problema.
Main
ainda executa apenas uma função (renderizando a tela principal), mas você vê todos esses métodos com os quais estamos lidando agora:
class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [], isMobileSidebarOpen: false }; componentDidMount() { this.loadPosts(); } loadPosts() {
Nosso componente se torna grande e volumoso, é difícil de entender. E com a expansão da funcionalidade, a situação só vai piorar.
O que deu errado?
Única razão
Vamos voltar à definição do princípio de responsabilidade exclusiva:
qualquer componente deve ter apenas um motivo para a mudança .
Anteriormente, alteramos a maneira como as postagens são exibidas, portanto tivemos que alterar nosso componente Principal. Em seguida, alteramos a maneira como a barra lateral se abre - e novamente alteramos o componente Principal.
Este componente tem muitos motivos não relacionados à mudança.
Isso significa que ele executa muitas funções .
Em outras palavras, se você puder alterar significativamente uma parte do seu componente e isso não levar a alterações na outra parte, o componente terá muita responsabilidade.
Separação mais eficiente
A solução é simples: você precisa dividir o componente Principal em várias partes. Como fazer isso?
Vamos começar de novo. A renderização da tela principal permanece de responsabilidade do componente Principal, mas a reduzimos apenas para exibir os componentes relacionados:
class Main extends React.Component { render() { return ( <Layout> <PostList /> </Layout> ); } }
Ótimo
Se mudarmos repentinamente o layout da tela principal (por exemplo, adicionar seções adicionais), então Principal também será alterado. Em outros casos, não teremos motivos para tocá-lo. Ótimo.
Vamos para o
Layout
:
class Layout extends React.Component { render() { return ( <SidebarDisplay> {(isSidebarOpen, toggleSidebar) => ( <div> <Header openSidebar={toggleSidebar} /> <Sidebar isOpen={isSidebarOpen} close={toggleSidebar} /> </div> )} </SidebarDisplay> ); } }
Isso é um pouco mais complicado.
Layout
é responsável por renderizar os componentes do layout (painel lateral / painel superior). Mas não sucumbiremos à tentação e daremos ao
Layout
responsabilidade de determinar se a barra lateral está aberta ou não.
Atribuímos essa função ao componente
SidebarDisplay
, que transmite os métodos ou estados necessários aos componentes
Header
e
Sidebar
.
(O exemplo acima é um exemplo do padrão Render Props via Children no React. Se você não estiver familiarizado com ele, não se preocupe. É importante que exista um componente separado que controle o estado aberto / fechado da barra lateral.)E então, a própria
Sidebar
pode ser bastante simples se for responsável por renderizar a barra lateral à direita.
class Sidebar extends React.Component { isMobile() {
Novamente, resistimos à tentação de inserir JSX para computadores / dispositivos móveis diretamente nesse componente, pois nesse caso, haverá dois motivos para a mudança.
Vejamos outro componente:
class PostList extends React.Component { state = { postsToHide: [] } filterPosts(posts) {
PostList
muda apenas se
PostList
a maneira como a lista de postagens é
PostList
. Parece óbvio, certo? É exatamente disso que precisamos.
PostLoader
muda apenas se
PostLoader
a maneira como as postagens são carregadas. E, finalmente, a
Post
muda apenas se alterarmos a maneira como a postagem é renderizada.
Conclusão
Todos esses componentes são pequenos e executam uma função pequena. As razões para as alterações nelas são fáceis de identificar e os próprios componentes são testados e corrigidos.
Agora, nossa aplicação é muito mais fácil de modificar: reorganize componentes, adicione novas e expanda a funcionalidade existente. Você só precisa olhar para um arquivo de componente para determinar para
que serve.
Sabemos que nossos componentes mudarão e crescerão com o tempo, mas a aplicação dessa regra universal ajudará a evitar dívidas técnicas e a aumentar a velocidade da equipe. Você decide como distribuir os componentes, mas lembre-se -
deve haver apenas um motivo para alterar o componente .
Obrigado por sua atenção e aguardamos seus comentários!