Skip to content

Instantly share code, notes, and snippets.

@reginadiana
Last active April 8, 2024 15:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reginadiana/883af9e508579bff821b343094de5d80 to your computer and use it in GitHub Desktop.
Save reginadiana/883af9e508579bff821b343094de5d80 to your computer and use it in GitHub Desktop.
Anotações de React

Introdução de React

JSX não é html. Ele é apenas uma sintaxe para React.createElement. Então, todo jsx que for escrito será convertido para React.createElement, e quem faz essa converssão é o babel. O jsx não pode ser interpretado pelo browser

document.createElement: retorna um elemento DOM.

React.createElement: retorna um objeto que representa o elemento DOM (virtual).

ReactDOM: é a lib que atualiza a verdadeira DOM baseado nas mudanças da DOM virtual.

Reconciliation é o processo de sincronizar o virtual DOM com o DOM real.

Whenever a component's state changes, React calls the render methods on the nodes again and it compares the result with the previous tree of React elements. The library is smart enough to figure out the minimum set of operations required to apply the expected changes on the screen

jquery foi lançado em 2006 e foi tão utilizado quanto o React hoje.

Single Page Aplication significa que temos uma única paǵina que fará as alterações quando necessário.

Patterns

Coleção de boas práticas que encontrei lendo livros, artigos e assistindo aulas, palestras

  1. Preferir usar componentes funcionais, a menos que precisemos de algo que ele não tenha, como state interno, lifecycle e event handles.

  2. Manter componentes pequenos, para que seja mais fácil de testar, dar manutenção e reaproveitar.

  3. Usar o defaultProps e o a lib prop-types para definir valores default para as props e seu tipo, além de especificar se alguma props é obrigatória por exemplo.

  4. Não use o index como key ao interar elementos que podem mudar a ordem. Ao invés disso, podemos usar o próprio id.

  5. Sempre adicione valores no array de dependencias do useEffect, para ficar mais claro sobre quando as funções chamadas dentro dele.

  6. Quebre o código em pequenos componentes para que a leitura do código fique mais clara.

  7. Nomear os componentes em UpperCase, assim como o nome deste arquivo.

  8. Prefira não iniciar o estado de um componente com um dado vindo como props de um componente pai. Primeiro porque teremos 2 fontes da verdade (a props, e o estado inicializado), e segundo porque, se por algum motivo essa props mudar, o estado não será "re-inicializado" ou "atualizado", pois o state já foi inicializado e isso só acontece uma vez.

Hooks

useState

O useState: é um hook que define uma variável reativa. Toda vez que o setState é chamado, o componente é atualizado. Portanto, o setState sempre precisa ser chamado por algum evento prévio como o onChange, onClick, etc. Caso contrário, teremos renderizações infinitas.

A definição do estado incial pode ser feita usando um callback, assim como ao atualiza o estado (neste caso, teremos acesso ao estado anterior antes do componente ser atualizado).

Como o processo de atualização do state é assincrono, ou seja, não acontece imediatamente após chamar o setState, podemos atualizá-lo a partir de uma função e não um objeto, permitindo que esse processo ocorra de modo sincrono.

Esse método é muito util quando queremos atualizar o state para um novo valor que dependa do anterior.

// Ao invés disso
this.setState({ showPagination: !this.state.showPagination });

// Prefira
this.setState(( state, props) => {
  return { showPagination: !state.showPagination };
));

useEffect

O useEfefct é um hook do rect que permite executar funções/código dependendo do estado de ciclo de vida do componente.

useEffect(() => 
  console.log("Vou ser chamado toda vez que o componente for montado e/ou atualizado")
) // É executado apenas uma vez

Porém, se adicionarmos uma chamada de atualização de estado nesse caso, causaremos um loop infinito

const [isLoading, setIsLoading] = useState(false);

useEffect(() => 
  setIsLoading(prev => !prev) // Atualiza compontente
) // É executado toda vez que o componente é renderizado, pois não há dependencias
useEffect(() => 
  console.log("Vou ser chamado toda vez que o componente for montado")
, []) // Não tem dependencias. É executado apenas uma vez
useEffect(() => 
  console.log("Vou ser chamado toda vez que o estado for atualizado")
, [estado]) // Depende do estado. Se receber mais estados, o effect será acionado quando qualquer um dos estados sofrer alteração
useEffect(() => { 
  return () => { 
   console.log("Vou ser chamado toda vez que o componente for desmontado") 
  } 
});
  • Quando precisamos realizar alguma ação que depende do estado dentro do useEffect, ele precisa ser usado como dependencia para que seja chamado;

  • Porém, não é uma boa chamar o set para atualizar o estado que está como dependencia, porque assim o useEffect vai ser chamado o tempo todo;

  • Podemos ter várias dependencias dentro do effect;

  • Podemos ter vários effects em um componente, e é uma boa prática separá-los que as funções e dependencias tem responsabilidades diferentes.

  • O useEffect só é chamado após a renderização do componente.

  • O useEffect só pode retonar funções. Ex: quando declaramos um async logo de cara ele gera um erro pois entende que estamos tentando retornar uma promisse e não uma função.

  • O useEffect é executado após a renderização do componente. E ao realizar requisições dentro dele, estamos fazendo com que o processo de carregamento da página seja mais lento. O ideal é que as requisições possam ocorrer em paralelo com a montagem. Uma das formas de se fazer isso é usando o useQuery.

  • Unnecessary dependencies may cause your Effect to run too often, or even create an infinite loop.

  • Ele nos obriga a colocar no array de dependencias todos os valores que sejam reativos, sejam eles props, estados, etc, a menos que transformemos esses dados em não-reativos.

  • É uma boa prática de performance não fazer manipulação de dados dentro do useEffect, mas sim no topo do componente.

useRef

O useRef é uma maneira do React pegar um elemento .jsx como referencia, ou seja, toda vez que quisermos pegar determinado elemento via documentGetElementById, ou querySelect, podemos simplesmente usar o useRef para isso.

O legal do useRef é que ao atribuirmos um valor para ele e atualizarmos o componente por algum motivo, ele não se perde, diferente de quando declaramos esse mesmo valor em escopo global usando var, let, const, whatever.

O objeto retornado persistirá durante todo o ciclo de vida do componente.

  • O componente não é atualizado quando valor de useRef muda. Se quisermos, podemos usar um callback pra ser chamado quando isso ocorrer.

O context API é nativo a partir da versão 16

Criando um contexto no React

const Context = React.createContext()

Provider

É um componente que "fornece" os dados do contexto, bem como as suas mudanças aos seus "consumidores" (componentes filhos deste provedor) do mesmo contexto.

/* A props "value" precisa necessáriamente ter este nome */
<Context.Provider value={value}>
...
</Context.Provider>

Consumer

É um componente que consome/recebe os dados do contexto. Seu componente filho espera receber uma função (que recebe as props) do contexto que retorne um componente. Se um componente Consumer for renderizado sem um componente de Provider como pai, as props recebidas serãoas que formam informadas como default ao criar o contexto, e não as que foram enviadas pelo componente de Provider.

<Context.Consumer>
{(value) => <ChildComponent />}
</Context.Consumer>

Atualizando valores do contexto

// Criando o contexto
const ThemeContext = React.createContext({ 
  theme: 'black', // Caso de valor qualquer
  toogleTheme: () => {} // Futuro setState
})

// Provendo contexto
const [theme, setTheme] = useState('');
const value = {theme, setTheme}

<ThemeContext.Provider value={value}>
...
</ThemeContext.Provider>

// Consumindo contexto

<ThemeContext.Consumer>
{(value) => <ChieldComponent /> }
</ThemeContext.Consumer>

// ChieldComponent
// Atualiza contexto

const UseThemeContext = React.useContext(ThemeContext)

UseThemeContext.setTheme('white')

Code Splitting

Dividir o código pode te ajudar a carregar somente o necessário ao usuário, o que pode melhorar drasticamente o desempenho de sua aplicação.

A função do React.lazy é permitir a renderização

React Strict Mode

Esse "modo estrito" incova duas vezes a renderização dos componentes quando o estado é atualizado, a fim de evitar efeitos colaterais.

React PDF

Recurso Descrição
Page Representa uma unica página
Wrap Quebra de documento
Breakble Components Tenta preencher todo espaço restante antes de pular para uma nova página
Unbreakble Components Se não houver espaço suficiente no restante da página, o conteúdo será renderizado na página seguinte
Break Força a quebra do documento para continuar na próxima página
Fixed Renderiza algum componente em todas as páginas do documento, como por exemplo o cabeçalho e rodapé
PDFDownloadLink Permite que seja feito o downlaod do documento
BlobProvider Habilita o acesso ao blob data
usePDF É um hook customizado do React que nos dá acesso ao documento

Styled Components

  • Gera uma classe única para cada instancia do styled, então não corremos o risco de ter classes duplicadas.

  • É altamente recomendado (mas não obrigatório) usar um plugin do babel. Ele oferece muitos beneficios como mais legibilidade para o nome das classes, compatibilidade com renderização server-side, bundles menores e mais.

  • Em alguns casos, voce pode querer aproveitar o mesmo estilo de um styled em diverentes tags html ou componentes. Isso é possivel usando o parametro as no uso do styled, assim o elemento renderizado será aquele especificado no as, mas com todas as propriedades de estilo.

Webpack

Webpack é um empacotador de módulos para aplicações JS em um unico arquivo. Ele suporta fontes, css, imagens, html, js e plugins.

Principais conceitos do Webpack:

🔵 Entry: utilizando grafo, o webpack precisa de um ponto de entra para buscar todos os módulos e dependencias. Exemplo:

    entry: {
      app: glob.sync("./vendor/**/*.js").concat(["./js/app.js"]),
    }, 

🔵 Output: para determinar quais são os módulos que ele vai exportar. Exemplo:

    output: {
      filename: "[name].js",
      path: path.resolve(__dirname, "../priv/static/js"),
      publicPath: "/js/",
    },

🔵 Loaders: para permitir que o webpack gerencie arquivos que não são do tipo js. Ele também pode converter a versão do javascript. Exemplo:

    module: {
      rules: [
        {
          test: /\.vue$/, // Define os arquivos que serão filtrados, filtra todos os arquivos com extensão .vue
          exclude: /node_modules/,
          loader: "vue-loader",
        },
        {
          test: /\.js$/, // Filtra todos os arquivos com extensão .js
          exclude: /node_modules/,
          use: { // Define os módulos que serão utilizados
            loader: "babel-loader",
          },
        },
        {
          test: /\.[s]?css$/,
          use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
        },
        {
          test: /\.svg$/i,
          type: "asset/inline",
        },
        {
          test: /\.(png|jpg|jpeg|gif)$/i,
          type: "asset/resource",
        },
        {
          test: /\.(woff|woff2|eot|ttf|otf)$/i,
          type: "asset/resource",
        },
      ],
    },

🔵 Plugins: podem ser usados para otimização de pacotes, minificação, injeção de scripts e injeção de variáveis de ambiente. Exemplo:

    plugins: [
      new MiniCssExtractPlugin({ filename: "../css/app.css" }),
      new CopyWebpackPlugin({
        patterns: [{ from: "static/", to: "../" }],
      }),
      new webpack.DefinePlugin({
        'process.env.BUILD': JSON.stringify('web')
      }),
      new VueLoaderPlugin(),
    ],

Podemos definir plugins internos e externos dentro do webpack

🔵 Mode: utilizado para abordagem de configuração do zero. É possivel configurar módulos como production, development ou none. O default é development. Exemplo:

mode: options.mode || "production",

Production: trás otmizações internas e gera um arquivo final.

Development: é executa 3 plugins básicos

None: não passamos nenhuma configuração

📝 Chaves (keys) devem ser unicas apenas entre elementos irmãos

📝 O parametro e registra o que aconteceu em um evento


Desenvolvimento de aplicações para internet com ReactJS

Stateful: Usa estados, possui gerenciamento de estados no componente e é construído usando classes em JS. É o ciclo de vida no React

Stateless: Não usa estados, não possui gerenciamento de estados no componentes e é construido usando funções em JS. Usado para renderizar imagens, textos comuns, etc

Formulários matem um estado interno ao próprio DOM

A diferença ao utilizar o useState invés de uma variável comum é poder dizer ao React que quando essa variável mudar ele precisa renderizar novamente os componentes dependentes dela.

Performance

  • React is fast enough by default and you do not need to do anything more to improve the performance of your application.

  • When React has to display a component, it calls its render method and the render methods of its children recursively. The render method of a component returns a tree of React elements, which React uses to decide which DOM operations have to be done to update the UI.

  • Alterar a DOM diretamente é um processo custoso para o React e consequentemente diminui a performance das nossas apps.

React Hook Form

O React Hook Form adota o uso de entradas não controladas em vez de depender do estado: apenas as alterações de entradas são rerrenderizadas, não o formulário inteiro. Tecnicamente, ele usa ref por baixo dos panos, diferentes de outras libs que usam o state. Essa abordagem torna os formulários mais eficientes e reduz o número de novas renderizações.

Em uma solução comum, usariamos um useState para o campo e ao triggar o onChange do input atualizariamos esse estado, fazendo com que o componente seja atualizado toda hora, comprometendo a performance.

image

Aqui nós temos um caso de High Order Function, que é o ato de passar uma função como argumento para outra função

📚 handleSubmit: vai passar os dados do formulário quando a validação do formulário for bem-sucedida. É sempre chamada ao submeter o formulário.

📚 onSubmit: vai ser chamado quando o formulário for válido após ter passado pelo handleSubmit

📚 register: método que declara a validação para o campo e torna disponivel o valor dele para ser usado no hook form. Dentro dele há todos os parametros que passariamos para o input, como onChange, onBlur, etc.

📚 reset: apaga ou reseta o state do hook form, especificamente os valores e mensagens de erro.

📚 @hookform/error-message: fornece um componente para exibir as mensagens de erro que foram extraidas de useForm

image

useController: É um hook que funciona de forma similar a Controller, por meio do qual é possível passar as props diretamente para os campos do formulário, conforme o exemplo da documentação:

image

O React Hook Form suporta validação de formulário baseada em schema (representação da estrutura de dados do formulário), como o Yup ou Zod. Para isso precisamos instalar a lib @hookform/resolvers

O useForm prove o método formState, que prove dentro dele os seguintes métodos:

isDirty: indica se o evento dirty ocorreu para qualquer um dos campos

dirtyFields: objeto que retorna os campos que sofreram a ação de dirty

isValid: indica se o formulário está valido

errors: objeto que contém chave (name do campo) e valor (erro do campo)

isSubmitted: indica se o usuário submeteu o formulário pelo menos uma vez

touchedFields: objeto que contém os campos que sofreram a ação de touched

Vale lembrar, que touch significa que o usuário interagiu com o campo de forma "superficial", seja clicando nele, selecionado com tab, etc, mas isso não significa que o campo esteja dirty, pois isso só ocorre quando um valor é inserido de fato

Aplicamando para campos com checkbox, o register é repetido para cada uma das opções:

image

Lidando com arrays

Temos o useFielddArray

  • Usar o field.id que é gerado automaticamente por ele como key, e não o index.

Referencias

  • Podemos fazer transformações de dados usando o método .transform
  • O Zod só trabalha com tipos primitivos do javascript como boolean, string, number, etc. Se quisermos algo diferente podemos usar o .instanceOf
  • .refine: retorna o dado especificamente do campo que foi chamado. Podemos adicionar validações customizadas para ele.
  • .superRefine: retorna os dados de todos os campos. Podemos adicionar validações customizadas para o campo que foi chamado que dependenda dos valores de outros campos do formulário.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment