Pressione enter para ver os resultados ou esc para cancelar.

CSS Modules + React: conceitos básicos

Antes de mais nada, é preciso instalar as dependências para criar um site com React. Vale lembrar que partimos do ponto onde paramos no artigo anterior. Se você não leu, dê uma olhada antes de continuar.

npm i -D babel-preset-react react react-dom

Precisamos adicionar uma configuração no arquivo .babelrc para que o Babel use o plugin de React que acabamos de instalar:

{
"presets": ["es2015", "react"]
}

Aos poucos vamos refatorando os componentes já criados para usar eles como componentes do React. Vamos começar pelo arquivo src/index.js.

import React, { Component } from 'react'

export default class App extends Component {
  render () {
    return (
      <html>
        <body>
          <h1>
            React is working :B
          </h1>
        </body>
      </html>
    )
  }
}

Por fim, precisamos adicionar algum elemento com id igual a ‘react’ no markup, pois é no lugar dele que será renderizada a aplicação React (linha 5 do arquivo src/index.js). Sendo assim, temos nosso index.html:

<!DOCTYPE html>
<html lang="pt-br">
  <head>
    <meta charset="UTF-8">
    <title>CSS Modules Example</title>
    <link rel="stylesheet" href="dist/styles.css">
  </head>
  <body>
    <div id="react"></div>
    <script src="dist/bundle.js"></script>
  </body>
</html>

Rodando o comando webpack e abrindo o arquivo src/index.html no navegador, já veremos o React em ação 😉

yes

Quem cuida de quê?

Agora que já temos o React rodando, podemos ver como vamos utilizar o CSS Modules junto de seus componentes para melhor aproveitar o que esse ecossistema nos oferece. Aí que começam os questionamentos, entre eles o que pra mim é o principal deles nesse caso: quem deve cuidar da aparência de um elemento na tela?

guess who

Usando React, podem haver várias formas de abordar isso. Vamos começar refatorando o componente de link que já temos na nossa aplicação, movendo os arquivos src/link.js e src/link.css para src/components/Link/Link.js e src/components/Link/Link.css, respectivamente. Refatorando o arquivo Link.js, temos:

import React from 'react'
import styles from './Link.css'

export const Link = () => (
  <a className={ styles.link } href='#'>
    Try out now!
  </a>
)

export default Link

Agora vamos usar esse componente dentro do src/App.js para que ele apareça na tela:

import React, { Component } from 'react'
import Link from '../components/Link/Link'

export default class App extends Component {
  render () {
    return (
      <div>
        <h1>
          React is working :B
        </h1>
        <Link>
          Try out now!
        </Link>
      </div>
    )
  }
}

A esse ponto você já está de saco cheio de rodar o comando webpack, então é óbvio que rodou webpack –help e descobriu que também pode rodar ele com a flag –watch, o que faz com que ele recompile seu código a cada arquivo salvo. Assim, já percebeu também que o link está lá, com o mesmo estilo de antes. Agora é que começa a brincadeira.

E se eu quisesse inserir o mesmo link mas com fundo vermelho? No artigo anterior vimos que seria possível criar outro componente com esse estilo diferente, mas também vimos que criar um componente diferente apenas por uma propriedade de CSS não faz muito sentido. Aqui o React pode nos ajudar, e muito! Vamos primeiro criar algumas classes que vão adicionar essa cor de fundo diferente ao nosso componente (arquivo Link.css):

.link {
  font-size: 0.8rem;
  color: white;
  background-color: orange;
  padding: 0 0.5rem;
  border-radius: 0.5rem;
}

.red {
  background-color: red;
}

.blue {
  background-color: blue;
}

.yellow {
  background-color: yellow;
}

Aí já temos o que parece um paradoxo sobre quem cuida da aparência do componente: eu quero inserir ele no container App e dizer que cor vai ter, mas estou escrevendo os estilos diretamente no CSS do link.

hein?

O motivo é simples: o React colabora bastante quando precisamos controlar propriedades de um componente. Se um componente provê propriedades que podem ser controladas pelo container que vai carregá-lo, então ele poderá se comportar de maneiras diferentes sem que seja criado outro componente apenas para este fim. Obviamente, podemos usar este recurso para alterar também a aparência.

Controlando os estilos do componente

Para isso, vamos precisar de um módulo chamado classnames. Esse módulo vai permitir que possamos incluir mais de uma classe por componente:

npm install classnames --save

Agora vamos fazer com que o Link possa ter as classes que acabamos de criar no Link.css de acordo com as propriedades que receber:

import React from 'react'
import styles from './Link.css'
import classnames from 'classnames'

export const Link = ({
  children,
  color,
  className,
}) => (
  <a
    className={
      classnames(
        styles.link,
        styles[color],
        className
      )
    }
    href='#'
  >
    { children }
  </a>
)

export default Link

O que foi mudado no arquivo acima

  • import da biblioteca classnames, que permite que um componente do React receba mais de uma classe na propriedade className
  • propriedade color, que controlará as variações de cores recém implementadas no CSS
  • propriedade className, para que o componente pai possa passar uma classe específica para o link
  • na função classnames, temos os seguintes argumentos:
    • styles.link, que é a classe que já estava sendo aplicada
    • styles[color], que aplicará uma classe de acordo com a propriedade color
    • className, que aplicará a classe descrita na propriedade className vinda do componente pai

Para testar, basta atualizar este componente no container App:

<Link color="red">
  Try out now!
</Link>

A propriedade color recebeu o valor “red”, o que fez com que style[color], no componente Link, fosse traduzido para styles.red, que é uma classe que possui estilos declarados no Link.css (que é o arquivo importado no componente Link). Sendo assim, os estilos foram aplicados e o botão ficou com fundo vermelho.

Agora suponhamos que nesse container específico o botão terá de ficar com um espaço à sua esquerda. A estratégia de criar uma propriedade que controle isso no componente funcionaria, mas caso esse seja um requisito muito específico pode não fazer muito sentido ter uma propriedade. Foi para isso que foi declarada a propriedade className no Link e que ela foi passada como um dos argumentos da função classnames. Quando eu declarar um className para esse componente dentro de outro, a classe aplicada corresponderá aos estilos declarados no componente pai.

App.js

import React, { Component } from 'react'
import Link from '../components/Link/Link'
import styles from './App.css'

export default class App extends Component {
  render () {
    return (
      <div>
        <h1>
          React is working :B
        </h1>
        <Link color="red" className={ styles.link }>
          Try out now!
        </Link>
      </div>
    )
  }
}

App.css

.link {
  margin-left: 5rem;
}

Vale notar: o componente Link tem styles.link declarado em seu className, e no App ele foi aplicado também com styles.link no className. As classes parecem iguais, mas são bastante diferentes, porque depois de compilar uma vai começar com App_link e a outra com Link_link.

Um grande mundo adiante

Agora que entramos no mundo do React, há muita coisa para se explorar que poderá ajudar a usar CSS Modules no seu potencial máximo. Este artigo foi apenas um exemplo do que pode ser feito, pois as possibilidades das ferramentas que estamos usando vão muito além e pretendo chegar lá.

Por isso, se possível comente suas dúvidas e feedbacks para que o próximo artigo seja de grande utilidade a quem está entrando nesse mundo.