Zup - Style Guide
Os padrões que iremos adotar para serem utilizados em nossos projetos.
Indice
React and Javascript Style Guide
Este guia foi criado para mantermos o estilo de código React que adotamos aqui na Zup, e algumas práticas que nós consideramos ser adequadas. Nosso estilo é baseado no Airbnb com algumas modificações.
Objetivo
Qual o propósito de utilizarmos um Style Guide? O principal objectivo é mantermos uma única forma de escrita, porém também ganhamos:
- Melhor Legibilidade de código
- Melhor manutenção do código
- Ganho de tempo em code reviews
- Padrão de desenvolvimento
- Boas práticas de programação
- Clean Code
- Entre outros grandes benefícios
Instalação
yarn add --dev eslint@4.19.1 eslint-config-zup-react
Crie um arquivo .eslintrc.js
na pasta raiz do seu projeto com o seguinte conteúdo:
module.exports =
Rules
Extensão de componentes React
- Ao criar um arquivo React sempre utilize a extensão
.jsx
Button/
├── index.jsx
Criação de componentes com folha de estilo
- Quando necessário criar um componente que terá estilos, sempre opte por
styled-components
e com a seguinte estrutura:
Button/
├── index.jsx
└── styled.js
Importando Component
- Sempre que for extender uma classe com Component ou PureComponent faça a destruturação na importação.
// Badimport React from 'react'class Classe extends React.Component // Goodimport React, { Component } from 'react'class Classe extends Component
Criação de Classes
// Very Badimport React from 'react'const Classe = React.createClass({ render() { .... }}) // Badimport React from 'react'class Classe extends React.Component { render() { .... }} // Goodimport React, { Component } from 'react'class Classe extends Component { render() { .... }}
Stateless Component
- Prefira utilizar a sintaxe funcional para componentes sem estado e em
dumb components
.
const Title = (props) => ( <h1>{props.title}</h1>)
Stateful Component
- Prefira utilizar a sintaxe de classes para componentes que possuem conhecimento do estado, em container e componentes que utilizem lifecycles.
class Title extends Component { render () { return ( .... ) }}
State
- Caso seja necessário criar um estado local na sua classe utilize a seguinte abordagem:
// Badclass Example extends Component { componentWillMount() { this.state = { loading: true } }} // Godclass Example extends Component { constructor() { super() this.state = { loading: true } }} // Bestclass Example extends Component { state = { loading: true }}
Adição de vírgula no último elemento de um objeto
- Na utilização de objetos, sempre adicione vírgula no último element, isso irá auxiliar na visualização do git diff, caso haja adição de um novo elemento na última posição.
// Badexport { Provider, Consumer} // Goodexport { Provider, Consumer,}
Arrow function
- Sempre prefira escrever funções com
arrow functions
, principalmente se o retorno couber apenas em uma linha, e quando houvercallbacks
com funções anônimas.
// Very Badfunction double(array) { return array.map(function(item) { return item * 2 })} // Goodfunction double(array) { return array.map(item => item * 2)} // Bestconst double = array => array.map(item => item * 2)
Setando uma variável
- Sempre que possível, utilize const na inicialização de qualquer variável.
// Badvar a = 1 // Goodconst a = 1
Template Strings
- Dê preferência ao uso de template strings na concatenação de strings.
// Badconst person = { name: 'Isac'}const myName = "My name is "+ person.name+"." // Godconst person = { name: 'Isac'}const myName = `My name is ${person.name}.`
Ponto e vírgula
// Badimport React from 'react'; // Goodimport React from 'react'
Console.log
- Nunca deixe console.log() em seu código
// Badconst sum = (a, b) => { const result = a + b console.log(result)}
Comentários
- Nunca deixa comentários em seu código
// Bad// Função que soma dois elementosconst sum = (a, b) => a + b // Goodconst sum = (a, b) => a + b
Retorno de elementos com JSX
- Sempre que possível, omita o
return
// Badconst Bonus = () => { return ( <div> <h1>Zup Style Guide</h1> </div> )} // Goodconst Bonus = () => ( <div> <h1>Zup Style Guide</h1> </div>)
Destruturação de objetos
- Sempre que possível, utilize destruturação de objetos
// Badconst Title = (props) => ( <h1>{props.title}</h1>) // Goodconst Title = ({ title }) => ( <h1>{title}</h1>)
Exportação default
- Caso o seu arquivo contenha somente um elemento a ser exportado, utilize
export default
class ClasseNameA extends Component { render() { .... }} export default ClasseNameA
Englobar elementos em JSX
- Sempre que retornar um elemento
JSX
, envolva em um elemento pai. Caso esteja utilizando versão superior a React 16.2, prefiraFragment
, ou sintaxe curta de Fragment.
// Badimport React from 'react' const NameA = () => ( <div> .... </div>) // Goodimport React, { Fragment } from 'react' const NameA = () => ( <Fragment> .... </Fragment>) // Bestimport React, { Fragment } from 'react' const NameA = () => ( <> .... </>)
Transferindo props
- Caso haja a necessidade de repassar props para outros componentes, defina-as e utilize nomes semânticos, ao invés de utilizar
spread
. Isso irá facilitar o entendimento do fluxo, e quais props estão sendo utilizadas. Evitando a passagem desnecessárias de outras.
// Badconst Button = props => ( <StyledButton {...props}> {props.children} </StyledButton>) // Goodconst Button = ({ primary, children }) => ( <StyledButton color={primary}> {children} </StyledButton>)
Bind em métodos
- Caso esteja sendo necessário criar bind para o contexto
this
, prefira utilizar métodos comarrow function
.
// Badclass MyComponent extends Component { constructor() { super() this.methodA = this.methodA.bind(this) } methodA() { ... }} // Goodclass MyComponent extends Component { methodA = () => { ... }}
Inicializando State
- React > 16.3: Não utilize componentWillMount para iniciar o seu state
// Badclass MyComponent extends Component { componentWillMount() { this.setState({ currentColor: this.props.defaultColor, palette: 'rgb' }) }} // Goodclass MyComponent extends Component { state = { currentColor: this.props.defaultColor, palette: 'rgb' }}
ComponentWillMount
- React > 16.3: Sempre prefira o uso do
componetDidMount
ao invez docomponentWillMount
, o mesmo será descontinuado na versão 17.
// Badclass MyComponent extends Component { componentWillMount() { ... }}// Goodclass MyComponent extends Component { componentDidMount() { ... }}
ComponentWillReceiveProps
- React > 16.3: Este é um exemplo de verificação de props para atualização do estado. Sempre que se deparar com tal situação, utilize
getDerivedStateFromProps
para realizar tal operação.ComponentWillReceiveProps
será descontinuado na versão 17.
// Badclass ExampleComponent extends Component { state = { isScrollingDown: false }; componentWillReceiveProps(nextProps) { if (this.props.currentRow !== nextProps.currentRow) { this.setState({ isScrollingDown: nextProps.currentRow > this.props.currentRow }) } }} // Goodclass ExampleComponent extends Component { state = { isScrollingDown: false, lastRow: null } getDerivedStateFromProps(nextProps, prevState) { if (nextProps.currentRow !== prevState.lastRow) { return { isScrollingDown: nextProps.currentRow > prevState.lastRow, lastRow: nextProps.currentRow } } return null }}
ComponentWillUpdate
- React > 16.3: Caso queira executar alguma ação após o componente receber alguma chamada externa, prefira o uso de
componentDidUpdate
, poiscomponentWillUpdate
será descontinuado na versão 17.
// Badclass ExampleComponent extends Component { componentWillUpdate(nextProps, nextState) { if (this.state.someStatefulValue !== nextState.someStatefulValue) { nextProps.onChange(nextState.someStatefulValue); } }} // Goodclass ExampleComponent extends Component { componentDidUpdate(prevProps, prevState) { if (this.state.someStatefulValue !== prevState.someStatefulValue) { this.props.onChange(this.state.someStatefulValue) } }}
Component ou PureComponent
PureComponent
é similar ao Component. A diferença está noshouldComponentUpdate()
. EmPureComponent
isto é feito de forma superficial no estado e props. UtilizePureComponent
somente em casos em que você saiba exatamente a estrutura das propriedades que irão ser recebidas pelo component. Em alguns casos, onde o seu componente sempre irá renderizar uma mesma estrutura, você pode utilizar para ganhar performance. Mais informações você vai encontrar na documentação do React.
Valores padrões em parâmetros
- Sempre que possível, crie valores padrões nos parâmetros da sua função
// Badconst getPrice = (amount, scale, currency) => { return priceNormalize(parseFloat(inScale(amount, scale), 10), currency)} // Goodconst getPrice = (amount = 0, scale = 2, currency = 'BRL') => { return priceNormalize(parseFloat(inScale(amount, scale), 10), currency)}
Classes - Padding Line
- When creating classes use blank line after
// Badclass MyComponent extends Component { componentDidMount() { ... }} // Goodclass MyComponent extends Component { componentDidMount() { ... }}
Return - Padding Line
- When return used requires a blank line between a variable declaration and a return statement
// Badrender () { const { name } = this.props return ( <h1> {name} </h1> )} // Goodrender () { const { name } = this.props return ( <h1> {name} </h1> )}