<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Raul Cesar</title>
    <description>The latest articles on DEV Community by Raul Cesar (@raulcesar54).</description>
    <link>https://dev.to/raulcesar54</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F971389%2F224d9b95-890a-4e6b-a862-c866c71aa075.jpeg</url>
      <title>DEV Community: Raul Cesar</title>
      <link>https://dev.to/raulcesar54</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/raulcesar54"/>
    <language>en</language>
    <item>
      <title>Componente Composto com React</title>
      <dc:creator>Raul Cesar</dc:creator>
      <pubDate>Sat, 12 Nov 2022 22:36:55 +0000</pubDate>
      <link>https://dev.to/raulcesar54/componente-composto-com-react-i72</link>
      <guid>https://dev.to/raulcesar54/componente-composto-com-react-i72</guid>
      <description>&lt;p&gt;Olá, me chamo Raul, atualmente sou dev front-end sênior e quero compartilhar com voces um pattern muito bacana, que venho adotando em meus projeto e podem deixar seus componentes muito mais reutilizáveis e escalaveis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WaxijyxH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pngdhnyrbo6930xf4mm6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WaxijyxH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pngdhnyrbo6930xf4mm6.gif" alt="Surprise" width="480" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;O pattern é denominnado &lt;strong&gt;composed components&lt;/strong&gt;, é considerado um pattern avançado e existe uma infinidade de materias a cerca deste pattern na web, porém, neste post vou tentar explicar da maneira mais clara que conseguir para facilitar o entendimento.&lt;/p&gt;

&lt;p&gt;Esse parttern consiste em construir componentes mais flexiveis e escalaveis, usando a Context Api para criar interações internas do componente, desta maneira, evitamos o prop drilling e não precisaremos criar estados fora do componente para gerenciar seu comportamento interno, isso ajuda a interação dos componentes filhos com seu componente pai e de quebra, podemos deixar seu componente infinitamente mais flexivel, esse parttern poder ser aplicado tanto em React Native quanto com React JS, neste post usarei o React JS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vamos iniciar o projeto
&lt;/h2&gt;

&lt;p&gt;Para estre projeto, vou utilizar &lt;a href="https://pt-br.reactjs.org/https://pt-br.reactjs.org/"&gt;React&lt;/a&gt;, Typescript, &lt;a href="https://pt-br.reactjs.org/"&gt;Styled-components&lt;/a&gt; e &lt;a href="https://react-icons.github.io/react-icons/icons?name=ai"&gt;React-icons&lt;/a&gt;, no fim deste post, vou anexar o codepen do projeto para vocês conseguirem testar e clonar.&lt;/p&gt;

&lt;h2&gt;
  
  
  O componente
&lt;/h2&gt;

&lt;p&gt;Para demonstrar o pattern vou criar este componente, um card com uma ação de abrir e fechar, ao abrir o card aparecera uma informação que pode ser qualquer coisa, desde um texto até um componente complexo.&lt;/p&gt;

&lt;p&gt;Criei esse &lt;a href="https://www.figma.com/file/ljHJjXd3mPaq6YoFhpw881/Composed-Card?node-id=0%3A1"&gt;Figma&lt;/a&gt;, caso queiram ter uma base do que seguir, também adicionei alguns desafios e features para vcs desenvolverem e praticarem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eOrpJaqi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hssmg9xtgfs4sfn1hsfi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eOrpJaqi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hssmg9xtgfs4sfn1hsfi.png" alt="Card do exercicio" width="633" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Parte 1 - Organizando a casa
&lt;/h2&gt;

&lt;p&gt;Meu primeiro passo foi criar a estrutura de pasta para armazenar meu componente, eu gosto de deixar o componente &lt;strong&gt;Pai&lt;/strong&gt; na raiz da pasta do componente, este componente &lt;strong&gt;Pai&lt;/strong&gt; vai ser o responsável por gerenciar o contexto e tambem será o cara que irei importar onde quero aplicar o componente.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Componente Pai&lt;/strong&gt; &amp;gt; Card&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_JMt6viy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u0sexy893z012oife56c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_JMt6viy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u0sexy893z012oife56c.png" alt="Raiz do componente" width="247" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Parte 2 - Criando o componente Card
&lt;/h2&gt;

&lt;p&gt;Sempre que posso eu divido meus componentes em 3 arquivos, um de estilo, um de props (usando typescript) e um de lógica (onde aplico as regras de negócio do componente).&lt;/p&gt;

&lt;p&gt;No index.tsx, temos a regra de negócio aplicada, criei um estado para gerenciar se os componentes filhos estão abertos ou fechados e criei uma função que tem o papel de inverter o valor do estado.&lt;/p&gt;

&lt;p&gt;Também criei um contexto passando o valor do estado e a função citada acima, partindo deste contexto usei o &lt;strong&gt;Provider&lt;/strong&gt; para englobar meus componentes filhos, a partir deste momento, meus componentes filhos tem acesso ao estado e a função criada anteriormente.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;index.tsx&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createContext, useState } from "react";
import { CardProps, CardPropsContext } from "./props";
import { CardContainer } from "./style";

export const CardContext = createContext({} as CardPropsContext);

export const Card = ({ children, ...props }: CardProps) =&amp;gt; {
  const [open, setOpen] = useState(false);
  function handleClose() {
    setOpen((e) =&amp;gt; !e);
  }
  return (
    &amp;lt;CardContext.Provider value={{ isOpen: open, handleClose: handleClose }}&amp;gt;
      &amp;lt;CardContainer {...props}&amp;gt;{children}&amp;lt;/CardContainer&amp;gt;
    &amp;lt;/CardContext.Provider&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;styled.tsx&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import styled from "styled-components";
export const CardContainer = styled.div`
  display: flex;
  align-items: center;
  background-color: #f4f4f4;
  padding: 8px;
  justify-content: space-between;
  border-radius: 4px;
  flex-direction: column;
  gap: 16px;
`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;props.ts&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";

export interface CardProps {
  Avatar?: React.ReactNode;
  children: React.ReactNode;
}
export interface CardPropsContext {
  isOpen: boolean;
  handleClose: () =&amp;gt; void;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Parte 3 - Criando o componente Button
&lt;/h2&gt;

&lt;p&gt;Neste componente vou buscar o contexto que criamos anteriormente usando o useContext do React.&lt;/p&gt;

&lt;p&gt;Apartir deste momento podemos invocar a função e alterar o estado do componente &lt;strong&gt;Pai&lt;/strong&gt; através do componente &lt;strong&gt;Filho&lt;/strong&gt;, passando essa função para o onClick do button já funciona bem, simples neh?! &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;index.tsx&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useContext } from "react";
import { CardContext } from "..";
import { Button } from "./style";
import { BsChevronDown, BsChevronUp } from "react-icons/bs";
export const CardButton = () =&amp;gt; {
  const context = useContext(CardContext);
  return (
    &amp;lt;Button onClick={context.handleClose}&amp;gt;
      {context.isOpen ? &amp;lt;BsChevronUp /&amp;gt; : &amp;lt;BsChevronDown /&amp;gt;}
    &amp;lt;/Button&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;style.tsx&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import styled from "styled-components";

export const Button = styled.button`
  cursor: pointer;
  border: 0;
  width: 30px;
  height: 30px;
  border-radius: 100px;
  &amp;amp;:hover {
    background-color: #00000005;
  }
`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Parte 4 - Finalizando os componentes filhos
&lt;/h2&gt;

&lt;p&gt;Neste ponto, a única parte que ficou pendente é fazer o componente de corpo aparecer e desaparecer ao clicar no botão, para isso, importei o contexto como feito no passo anterior e busco a prop &lt;code&gt;isOpen&lt;/code&gt;, para criar uma condicional e mostrar o &lt;code&gt;children&lt;/code&gt; do componente &lt;code&gt;CardBody&lt;/code&gt; caso &lt;code&gt;isOpen&lt;/code&gt; etiver com valor verdadeiro.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;index.tsx&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useContext } from "react";
import { CardContext } from "..";
import { CardBodyStyle } from "./style";

export const CardBody: React.FC = ({ children }) =&amp;gt; {
  const context = useContext(CardContext);

  return context.isOpen ? &amp;lt;CardBodyStyle&amp;gt;{children}&amp;lt;/CardBodyStyle&amp;gt; : &amp;lt;&amp;gt;&amp;lt;/&amp;gt;;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;style.tsx&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import styled from "styled-components";

export const CardBodyStyle = styled.div`
  display: flex;
  flex-direction: column;
  background: #e1e1e180;
  width: 100%;
  min-height: 40px;
`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Parte 5 - Voltando e finalizando componente pai
&lt;/h2&gt;

&lt;p&gt;Vamos voltar no componente &lt;strong&gt;Pai&lt;/strong&gt; e vamos trazer esses dois componentes que criamos para dentro dele, desta maneira, a forma de escrita e &lt;code&gt;import&lt;/code&gt; dos componentes fica mais claro e explicito.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;index.tsx&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createContext, useState } from "react";
import { CardButton } from "./cardButton";
import { CardBody } from "./cardBody";
import { CardProps, CardPropsContext } from "./props";
import { CardContainer } from "./style";

export const CardContext = createContext({} as CardPropsContext);

export const Card = ({ children, ...props }: CardProps) =&amp;gt; {
  const [open, setOpen] = useState(false);
  function handleClose() {
    setOpen((e) =&amp;gt; !e);
  }
  return (
    &amp;lt;CardContext.Provider value={{ isOpen: open, handleClose: handleClose }}&amp;gt;
      &amp;lt;CardContainer {...props}&amp;gt;{children}&amp;lt;/CardContainer&amp;gt;
    &amp;lt;/CardContext.Provider&amp;gt;
  );
};

Card.Button = CardButton;
Card.Body = CardBody;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Parte 6 - Aplicando o componente
&lt;/h2&gt;

&lt;p&gt;Está é a ultima parte abordada no post, finalizando este ponto teremos o componente pronto e o pattern aplicado, o resto fica a critério de vcs aplicarem o restante do layout, no codepen anexado ao fim terá todo o projeto desenvolvido.&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;app.tsx&lt;/code&gt; vou aplicar o componente e apartir deste momento temos uma infinidade de possibilidades, desde, remodelar aonde cada componente fica e editar seus estilos individualmente sem prejudicar seu funcionamento padrão e melhor, sem precisar criar estados desnecessários para gerenciar o comportamento do componente.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;app.tsx&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Card } from "./components/card";
import "./styles.css";

export default function App() {
  return (
    &amp;lt;div className="App"&amp;gt;
      &amp;lt;Card&amp;gt;
        &amp;lt;div
          style={{
            display: "flex",
            flexDirection: "row",
            alignItems: "center",
            width: "100%",
            gap: 16
          }}
        &amp;gt;

          &amp;lt;div style={{ marginLeft: "auto" }}&amp;gt;
            &amp;lt;Card.Button /&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;Card.Body&amp;gt;
          &amp;lt;h1&amp;gt;Teste&amp;lt;/h1&amp;gt;
        &amp;lt;/Card.Body&amp;gt;
      &amp;lt;/Card&amp;gt;
       &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Acho que neste ponto, voçês tem algo parecido com isso.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_-qjluhY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8oivdndmgx0wpkfksyb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_-qjluhY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8oivdndmgx0wpkfksyb9.png" alt="Componente fechado" width="548" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A6M_icNC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wav0c2xcs3yvuw0e6rua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A6M_icNC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wav0c2xcs3yvuw0e6rua.png" alt="Componente aberto" width="540" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gente apartir deste momento podemos pirar e montar uma infinidade de variações da aplicação deste componete, sem precisar criar milhares de condicionais e props no componente pai.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Este exemplo está presente no codepen, peço que acesse para testar mais a fundo e ver o código na pratica.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xmEgu6Dc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/os6vrquz853yur2hdge0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xmEgu6Dc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/os6vrquz853yur2hdge0.png" alt="Exemplos" width="584" height="729"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Finalizando
&lt;/h2&gt;

&lt;p&gt;Galera, agradeço a leitura deste post, espero ter ajudado este é o &lt;a href="https://codesandbox.io/s/compose-d3j2m5?file=/src/App.tsx:8682-8977"&gt;Codepen prometido&lt;/a&gt;, caso tenham duvidas podem me chama no &lt;a href="https://www.linkedin.com/feed/"&gt;Linkedin&lt;/a&gt; que respondo sempre que puder e me sigam no &lt;a href="https://github.com/raulcesar54"&gt;Github&lt;/a&gt;!, logo mais terá um projeto open source bacana lá!! Até mais e bons códigos pra vcs!!!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>reactnative</category>
      <category>react</category>
    </item>
  </channel>
</rss>
