• desenvolvimento
  • react

Como escrever código limpo no React

Como escrever código limpo no React

O código limpo é mais do que apenas código funcional. O código limpo é fácil de ler, simples de entender e bem organizado. Neste artigo, veremos oito maneiras de escrever um código React mais limpo.

Ao examinar essas sugestões, é importante lembrar que são exatamente isso: sugestões. Se você discordar de qualquer um deles, tudo bem. No entanto, essas são práticas que considero úteis para escrever meu próprio código React.

Bora lá?

1. Renderização condicional apenas para uma condição

Se você precisar renderizar condicionalmente algo quando uma condição for true e não renderizar nada quando uma condição for false, não use um operador ternário. Em vez disso, use o operador &&.

Como não fazer:

import React, { useState } from 'react'

export const ConditionalRenderingWhenTrueBad = () => {
  const [showConditionalText, setShowConditionalText] = useState(false)

  const handleClick = () =>
    setShowConditionalText(showConditionalText => !showConditionalText)

  return (
    <div>
      <button onClick={handleClick}>Toggle the text</button>
      {showConditionalText ? <p>A condição deve ser true!</p> : null}
    </div>
  )
}

Uma solução:

import React, { useState } from 'react'

export const ConditionalRenderingWhenTrueGood = () => {
  const [showConditionalText, setShowConditionalText] = useState(false)

  const handleClick = () =>
    setShowConditionalText(showConditionalText => !showConditionalText)

  return (
    <div>
      <button onClick={handleClick}>Toggle the text</button>
      {showConditionalText && <p>A condição deve ser true!</p>}
    </div>
  )
}

2. Renderização condicional em qualquer condição

Se você precisar renderizar condicionalmente uma coisa quando uma condição for  true  e renderizar outra coisa quando a condição for false, use um operador ternário.

Como não fazer:

import React, { useState } from 'react'

export const ConditionalRenderingBad = () => {
  const [showConditionOneText, setShowConditionOneText] = useState(false)

  const handleClick = () =>
    setShowConditionOneText(showConditionOneText => !showConditionOneText)

  return (
    <div>
      <button onClick={handleClick}>Toggle the text</button>
      {showConditionOneText && <p>A condição deve ser true!</p>}
      {!showConditionOneText && <p>A condição deve ser false!</p>}
    </div>
  )
}

Como fazer:

import React, { useState } from 'react'

export const ConditionalRenderingGood = () => {
  const [showConditionOneText, setShowConditionOneText] = useState(false)

  const handleClick = () =>
    setShowConditionOneText(showConditionOneText => !showConditionOneText)

  return (
    <div>
      <button onClick={handleClick}>Toggle the text</button>
      {showConditionOneText ? (
        <p>A condição deve ser true!</p>
      ) : (
        <p>A condição deve ser false!</p>
      )}
    </div>
  )
}

3. Boolean Props

A prop truthy pode ser fornecido a um componente com apenas o nome prop sem um valor como este: myTruthyProp. Escrever assim myTruthyProp={true} é desnecessário.

Como não fazer:

import React from 'react'

const HungryMessage = ({ isHungry }) => (
  <span>{isHungry ? 'Estou com fome' : 'Estou cheio'}</span>
)

export const BooleanPropBad = () => (
  <div>
    <span>
      <b>Esta pessoa está com fome: </b>
    </span>
    <HungryMessage isHungry={true} />
    <br />
    <span>
      <b>Esta pessoa está cheia: </b>
    </span>
    <HungryMessage isHungry={false} />
  </div>
)

Como fazer:

import React from 'react'

const HungryMessage = ({ isHungry }) => (
  <span>{isHungry ? 'Estou com fome' : 'Estou cheio'}</span>
)

export const BooleanPropGood = () => (
  <div>
    <span>
      <b>Esta pessoa está com fome: </b>
    </span>
    <HungryMessage isHungry />
    <br />
    <span>
      <b>Esta pessoa está cheia: </b>
    </span>
    <HungryMessage isHungry={false} />
  </div>
)

4. String Props

Um valor do tipo string em uma prop pode ser passado em aspas duplas sem o uso de chaves ou crases

Como não fazer:

import React from 'react'

const Greeting = ({ personName }) => <p>Hi, {personName}!</p>

export const StringPropValuesBad = () => (
  <div>
    <Greeting personName={"John"} />
    <Greeting personName={'Matt'} />
    <Greeting personName={`Paul`} />
  </div>
)

Como fazer:

import React from 'react'

const Greeting = ({ personName }) => <p>Hi, {personName}!</p>

export const StringPropValuesGood = () => (
  <div>
    <Greeting personName="John" />
    <Greeting personName="Matt" />
    <Greeting personName="Paul" />
  </div>
)
view raw

5. Event Handler Functions

Se uma função que lida com eventos passada para o componente recebe somente um argumento, você pode passá-la diretamente na prop, desta forma: onSubmit={handleSubmit}

Você não precisa quebrar a função em uma função anônima como este exemplo: onSubmit={e => handleSubmit(e)}

Como não fazer:

import React, { useState } from 'react'

export const UnnecessaryAnonymousFunctionsBad = () => {
  const [inputValue, setInputValue] = useState('')

  const handleSubmit = e => {
    setInputValue(e.target.value)
  }

  return (
    <>
      <label htmlFor="name">Name: </label>
      <input id="name" value={inputValue} onChange={e => handleSubmit(e)} />
    </>
  )
}

Como fazer:

import React, { useState } from 'react'

export const UnnecessaryAnonymousFunctionsGood = () => {
  const [inputValue, setInputValue] = useState('')

  const handleSubmit = e => {
    setInputValue(e.target.value)
  }

  return (
    <>
      <label htmlFor="name">Name: </label>
      <input id="name" value={inputValue} onChange={handleSubmit} />
    </>
  )
}

6. Passando componentes como Props

Ao passar um componente como um prop para outro componente, você não precisa envolver este componente passado em uma função se o componente não aceitar nenhuma prop.

Como não fazer:

import React from 'react'

const CircleIcon = () => (
  <svg height="100" width="100">
    <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
  </svg>
)

const ComponentThatAcceptsAnIcon = ({ IconComponent }) => (
  <div>
    <p>Below is the icon component prop I was given:</p>
    <IconComponent />
  </div>
)

export const UnnecessaryAnonymousFunctionComponentsBad = () => (
  <ComponentThatAcceptsAnIcon IconComponent={() => <CircleIcon />} />
)

Como fazer:

import React from 'react'

const CircleIcon = () => (
  <svg height="100" width="100">
    <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
  </svg>
)

const ComponentThatAcceptsAnIcon = ({ IconComponent }) => (
  <div>
    <p>Below is the icon component prop I was given:</p>
    <IconComponent />
  </div>
)

export const UnnecessaryAnonymousFunctionComponentsGood = () => (
  <ComponentThatAcceptsAnIcon IconComponent={CircleIcon} />
)

7. Undefined Props

Props undefined são ignoradas, então não se preocupe em fornecer um fallback se não houver problema a prop ter valor undefined.

Como não fazer:

import React from 'react'

const ButtonOne = ({ handleClick }) => (
  <button onClick={handleClick || undefined}>Click me</button>
)

const ButtonTwo = ({ handleClick }) => {
  const noop = () => {}

  return <button onClick={handleClick || noop}>Click me</button>
}

export const UndefinedPropsBad = () => (
  <div>
    <ButtonOne />
    <ButtonOne handleClick={() => alert('Clicked!')} />
    <ButtonTwo />
    <ButtonTwo handleClick={() => alert('Clicked!')} />
  </div>
)

Como fazer:

import React from 'react'

const ButtonOne = ({ handleClick }) => (
  <button onClick={handleClick}>Click me</button>
)

export const UndefinedPropsGood = () => (
  <div>
    <ButtonOne />
    <ButtonOne handleClick={() => alert('Clicked!')} />
  </div>
)

8. Definir estado que depende do estado anterior

Sempre defina o estado como uma função do estado anterior se o novo estado depender do anterior. As atualizações de estados no React podem ser agrupadas e não escrever as atualizações desta forma podem te levar a resultados inesperados.

Como não fazer:

import React, { useState } from 'react'

export const PreviousStateBad = () => {
  const [isDisabled, setIsDisabled] = useState(false)

  const toggleButton = () => setIsDisabled(!isDisabled)

  const toggleButton2Times = () => {
    for (let i = 0; i < 2; i++) {
      toggleButton()
    }
  }

  return (
    <div>
      <button disabled={isDisabled}>
        I'm {isDisabled ? 'disabled' : 'enabled'}
      </button>
      <button onClick={toggleButton}>Toggle button state</button>
      <button onClick={toggleButton2Times}>Toggle button state 2 times</button>
    </div>
  )
}

Como fazer:

import React, { useState } from 'react'

export const PreviousStateGood = () => {
  const [isDisabled, setIsDisabled] = useState(false)

  const toggleButton = () => setIsDisabled(isDisabled => !isDisabled)

  const toggleButton2Times = () => {
    for (let i = 0; i < 2; i++) {
      toggleButton()
    }
  }

  return (
    <div>
      <button disabled={isDisabled}>
        I'm {isDisabled ? 'disabled' : 'enabled'}
      </button>
      <button onClick={toggleButton}>Toggle button state</button>
      <button onClick={toggleButton2Times}>Toggle button state 2 times</button>
    </div>
  )
}

Conclusão

As práticas a acima não são específicas do React, mas sim boas práticas para escrever código limpo em JavaScript (ou qualquer linguagem de programação, nesse caso).

  • Extraia lógica complexa em funções claramente nomeadas.

  • Extraia números mágicos em constantes.

  • Use variáveis claramente nomeadas.

Divirta-se e boa programação!