Skip to content

Instantly share code, notes, and snippets.

@lavesan
Last active June 2, 2020 19:21
Show Gist options
  • Save lavesan/2dcabce491c760408b69d7d872c0df28 to your computer and use it in GitHub Desktop.
Save lavesan/2dcabce491c760408b69d7d872c0df28 to your computer and use it in GitHub Desktop.
React

Necessário:

  • Node.js
  • React.jsx

Comandos

Instalar o react:

npm i -g create-react-app

criar novo projeto:

create-react-app nomeDoProjeto

Rodar projeto:

npm start

da Virtual DOM

O que é?

O React salva os componentes da aplicação em um DOM virtual, basicamente é este snapshot do React

Vantagens

  • Mais rápido. Quando se altera a DOM em HTML puro, toda a página é recarregada. Com a DOM virtual, apenas os componentes que se alteraram são recarregados.

Sintaxe

  • Os arquivos React tem a extensão .jsx, mas um .js funciona do mesmo jeito
  • Sempre importar o React em todos .jsx e .js

import React from 'react'

  • No arquivo que irá reeinderizar algo (como o index.js). importar o ReactDom também para injetar o código na página
import ReactDOM from 'react-dom'
ReactDOM.render(HTML, document.getElementById('root'))

Componentes

  1. Sempre escrever com contra-barra '/' elementos tag sem fechamento!
  2. Por convenção, os coloco numa pasta chamada 'components'
  3. Os nomes dos componentes tem de ser MAIÚSCULOS para o plug-in do react reconhecê-lo como componente
  4. Quando exportar um componente do React, preciso mandálo envolto em 1 tag apenas
export default () => {
   <div>
      <h1>Passando</h1>
      <p>Tenho de envolvê-lo em 1 tag e passálo</p>
   </div>
}
  1. Posso não mandar uma tag que vai envolver também, só usar:
export default () => {
   <React.fragment>
      <h1>Passando</h1>
      <p>Só mandei os elementos, sem a div de lá de cima</p>
   </React.fragment>
}

ou

export default () => [
      <h1 key='titulo'>Passando</h1>,
      <p key='paragrafo'>Só mandei os elementos, sem a div de lá de cima</p>
]

Estas key são para o React colocar na tela de maneira mais fácil

Básico de componentes

Criando função default dentro do componente
pai

import tantoFazONome from './diretório'

filho

export default function() {
   return <h1>Texto</h1>
}

Criando funções em 1 arquivo que retornam 1 componente por função
pai

import {Componente1, Componente2} from './diretório'
// ou
// import ObjetoDeComponentes from './diretório'
// const Componente1 = ObjetoDeComponentes.Componente1

filho

export const Componente1 = function() {
   return <h2>Componente 1</h2>
}
export const Componente2 = function() {
   return <h2>Componente 2</h2>
}
// ou
// export default { Componente1, Componente2 }

Passando variáveis para o componente
pai:

<Componente1 variavel1="passou" ouAssim={Guilherme} />

filho:

export default function(props) {
  return <p>Tudo { props.variavel1 } e o nome dele é { props.ouAssim }!</p>
}

Passando variáveis dentro do HTML

export default function() {
  const variavel
   return <h1>Texto { variavel }</h1>
}

Componentes como classe

Criando

import React from 'react'

export default class Componente extends React.Component {
   // Este é um objeto padrão do React para alterar valor usando o this.setState()
   state = {
      nome: '';
   }
   
   render() {
      //Função chamada assim que inicia o componente
      const {nome} = this.state
      return (
         <input 
            type="text" 
            value="nome" 
            placeholder="Digite aqui..." 
            onChanges="e => setValue(e)" />
      )
   }
   
   // React NÃO TEM TWO WAY DATABINDING
   // Função para Alterar valor de input no React
   setValue(event) {
      this.setState({ nome: event.target.value })
   }
}

Props é um objeto que recebe os parâmetros do pai

Usando construtor

constructor() {
   super(props)
   
   // Salvando o contexto das funções que criei
   this.funcoesQueCriei = this.funcoesQueCriei.bind(this)
}

O construtor é opcional

Estilizando com .css, .scss, .sass...

  1. Importar arquivo css
import './diretório'
  1. Atribuir a classe ao elemento
<div className="nome-da-classe"></div>

Tipos de componente

  • Presentational (Skinny, Dumb, Stateless)
    • Componentes que reinderizam apenas um HTML e CSS recebendo props, sem state local.
  • Container (Fat, Smart, Stateful)
    • Utilizam um componente de apresentação e passam props para eles. Os states ficam neste componente

React Spring

Posso fazer animações com ela

npm i --save react-spring

Exemplo animando 1 componente:

import React from "react";
import { Spring } from "react-spring";
import "./styles.css";

function App() {
  return (
    <Spring
      from={{ opacity: 0.6, marginTop: -50 }}
      to={{ opacity: 1, marginTop: 50 }}
    >
      {props => (
        <div style={props} className="App">
          <article className="post">
            <h1>My first posts</h1>
            <p>
              Lorem ipsum dolor sit amet consectetur adipisicing elit.
              Cupiditate rerum reprehenderit consectetur porro similique
              reiciendis ex consequuntur tempore! Similique, pariatur
              harum.Facilis, accusantium quam labore incidunt soluta
              suscipit ipsa omnis.
            </p>
          </article>
        </div>
      )}
    </Spring>
  );
}

export default App;

Animando vários componentes:

import React from "react";
import { Trail } from "react-spring";
import "./styles.css";

const posts = [
  { title: "My first post", id: 1 },
  { title: "My second post", id: 2 },
  { title: "My Third post", id: 3 },
  { title: "My Fourth post", id: 4 }
];

function AllPosts() {
  return (
    <Trail
      items={posts}
      keys={post => post.id}
      from={{ marginLeft: -20, opacity: 0 }}
      to={{ marginLeft: 20, opacity: 1 }}
    >
      {post => props => (
        <div style={props} className="post">
             {post.title}
        </div>
      )}
    </Trail>
  );
}

export default AllPosts;

Posso mudar uma variável por exemplo:

import React from "react";
import ReactDOM from "react-dom";
import {Spring,config} from "react-spring";
import "./styles.css";

function NavBar() {
  return (
    <Spring from={{ number: 0 }} to={{ number: 100 }} config={config.slow}>
      {props => (
        <div style={{ width: props.number + "%" }}>
          <nav className="nav-bar">
            <a href="#">Home</a>
            <a href="#"> Posts</a>
            <a href="#">Contact</a>
          </nav>
        </div>
      )}
    </Spring>
  );
}

export default NavBar;

React Redux

Alterando o componente pai com algo do component filho

npm install --save redux react-redux

  • store
    • gravo os dados nele
  • reducers
    • digo o que quero alterar
  • actions
    • funções que enviam os dados para o reducer

dentro de um arquivo chamado store.js por exemplo

import { createStore } from 'redux'
import appReducer from './appReducer'

export default createStore(appReducer)

dentro de um arquivo chamadao appReducer.js por exemplo

const initialState = { text: 'Este texto' }

export default (state = initialState, action) => {
    switch (action.type) {
        case 'SET_TEXT':
            return { ...state, text: action.payload }
        default:
            return state
    }
}

coloco no index.js isso com as tags para linkar com o store

Apenas 1 por projeto

import ReactDOM from 'react-dom'
import React from 'react'
import { Provider } from 'react-redux'
import store from './store'
import App from './App'

ReactDOM.render(
   <Provider store={store}>
       <App />
   </Provider>, document.getElementById('root'))

crio um arquivo chamado appActions.js para sempre que este identificador for chamado, rodar a função

export default {
   setText(text) {
       return { type: 'SET_TEXT', payload: text }
   }
}

Para chamar no componente pai:

import React, { Component, Fragment } from 'react'
import { connect } from 'react-redux'
import appActions from './appActions'

class Children extends Component {
    setText() {
        this.props.dispatch(appActions.setText('Aquele texto'))
    }
    render() {
        return (
            <Fragment>
                <button onClick={() => this.setText()}>Mudar texto</button>
            </Fragment>
        )
    }
}

const ChildrenConnected = connect(store => ({ text: store.text }))(Children)

class App extends Component {
    render() {
        return (
            <Fragment>
                <h1>{this.props.text}</h1>
                <ChildrenConnected />
            </Fragment>
        )
    }
}

export default connect(store => ({ text: store.text }))(App)

React Helmet

Altero algum dado na tag Head do HTML

npm i --save react-helmet

import { Helmet } from 'react-helmet'

funcao = function() {
 return (
  <Helmet>
   <title>Mudei o título</title>
  </Helmet>
 )
}

React Router

Em React o mesmo HTML é reutilizado mudando apenas o BODY
Utilizado para mudar a url e criar rotas

npm install --save react-router-dom

Usando

import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import { Route, BrowserRouter as Router } from 'react-router-dom'
// Pages
import App from './App'
import Users from './users'
import Contact from './contact'

// Coloco as rotas aqui. Simples!
// O 'exact' é para carregar a página apenas quando é EXATAMENTE isso.
const routing = (
  <Router>
    <div>
      <Route exact path="/" component={App} />
      <Route path="/users" component={Users} />
      <Route path="/contact" component={Contact} />
    </div>
  </Router>
)
ReactDOM.render(routing, document.getElementById('root'))

Colocando links para as rotas

Assim posso colocar cabeçalhos!

import { Route, Link, BrowserRouter as Router } from 'react-router-dom'
...
const routing = (
  <Router>
    <div>
     <ul>
        <li>
          <Link to="/">Home</Link>
        </li>
        <li>
          <Link to="/users">Users</Link>
        </li>
        <li>
          <Link to="/contact">Contact</Link>
        </li>
      </ul>
      <Route exact path="/" component={App} />
      <Route path="/users" component={Users} />
      <Route path="/contact" component={Contact} />
    </div>
  </Router>
)
ReactDOM.render(routing, document.getElementById('root'))
```typescript
import React from 'react'
import { Route, Link } from 'react-router-dom'
const User = ({ match }) => <p>{match.params.id}</p>
class Users extends React.Component {
  render() {
    const { url } = this.props.match
    return (
      <div>
        <h1>Users</h1>
        <strong>select a user</strong>
        <ul>
          <li>
            <Link to="/users/1">User 1 </Link>
          </li>
          <li>
            <Link to="/users/2">User 2 </Link>
          </li>
          <li>
            <Link to="/users/3">User 3 </Link>
          </li>
        </ul>
        <Route path="/users/:id" component={User} />
      </div>
    )
  }
}
export default Users

Posso colocar links dentro de um componente também, só importar lá e usar!

Colocando uma página 404 (not found)

import { Route, Link, BrowserRouter as Router, Switch } from 'react-router-dom'
// Isso é uma página 404 que criei
import NaoEncontrado from 'naoEncontrado'
...
<Switch>
  <Route exact path="/" component={App} />
  <Route path="/users" component={Users} />
  <Route path="/contact" component={Contact} />
  <Route component={NaoEncontrado} />
</Switch>

Navegando pelo código

import React, { useEffect } from 'react';
import { useHistory } from 'react-router-dom';

const func = () => {
  // Adiciona uma instância do histórico para eu utilizar
  const history = useHistory();

  useEffect(() => {
    setTimeout(() => history.push('login'), 1000)
  }, [])
}

Query string

Lugar que reinderiza (ReactDom.render(...))

<Route path="/users:id" component={Users} />

Pegando o valor no componente

import React from 'react'
class Users extends React.Component {
  render() {
    console.log('Tudo que recebo: ', this.props)
    console.log('Parâmetros queryString: ', this.props.match.params)
    return <h1>Users</h1>
  }
}
export default Users

Aplicando um style num link selecionado para ir à uma página

NavLink

import {
  Route,
  NavLink,
  BrowserRouter as Router,
  Switch,
} from 'react-router-dom'
...
<ul>
  <li>
    <NavLink exact activeClassName="active" to="/">
      Home
    </NavLink>
  </li>
  <li>
    <NavLink activeClassName="active" to="/users">
      Users
    </NavLink>
  </li>
  <li>
    <NavLink activeClassName="active" to="/contact">
      Contact
    </NavLink>
  </li>
</ul>

Redirecionando

Nesse caso, sempre que o usuário dá um submit no formulário, ele é redirecionado à Home

import React from 'react'
class Contact extends React.Component {
  onSubmit = () => {
    this.props.history.push('/')
  }
  render() {
    return (
      <form>
        <input placeholder="name" type="name" />
        <input placeholder="email" type="email" />
        <button onClick={this.onSubmit}>Submit</button>
      </form>
    )
  }
}
export default Contact

Componentes de função

const ComponenteDeFuncao() {
   return <h1>Componente de classe</h1>
}

Vantagens

  • Mais rápido
  • Menos verbose

Hooks

Jeito de alterar o state e mais coisas do React com functionComponents

import React, { useEffect, useState } from 'react';

const Componente = () => {
   // useState
   // States de function components
   // 1º parâmetro do array: valor do state
   // 2º parâmetro do array: função para alterar o state
   const [var1, setVar1] = useState<number>(0);
   
   // useEffect
   // Lifecycle de function components
   // 1º parâmetro: função a ser executada
   // 2º parâmetro: regra para quando a função será executada
   // exp.: Array vazio ([]) executa assim que o componente é montado
   // exp.2: Array com um state ([var1]) executa sempre que ele é alterado
   // exp.3: Posso adicionar quantos states ou regras que eu quiser ([, var1])
   // Sempre que algum state alterar, esta função será chamada
   useEffect(() => {
      setVar1(10);
   }, []);
}

Tipando os hooks

https://fettblog.eu/typescript-react/hooks/#usestate

const Compoente = () => {
   const [var1, setVar1] = useState<string>('');
}

Explicando

  • O context-api é usado para enviar dados de pai para filho quando mais de 1 component usa os mesmos dados;
  • Posso usar o React-redux, mas ele seria um canhão para fazer uma besteirinha em alguns casos.

Provider

O componente que vai dar os dados

Consumer

O componente que vai receber os dados
Se ele não tiver um componente pai dando os dados, os dados padrões na criação do contexto serão usados

Exemplo

Neste caso há:

  • Um componente de loading que 2 ou mais telas usam

No componente pai (geralmente o app.js)

// O primeiro parâmetro que o React.createContext() recebe, pode ser um objeto ou uma string, informando o valor padrão para algo.
const LoadingContext = React.createContext({
    loading: false,
    message: null,
    showLoading: message => { },
    hideLoading: () => { }
})

class App extendes Component {
  state = {
    loading: false,
    message: null
  }
  
  showLoading = message => this.setState({
    loading: true,
    message
  })
  
  hideLoading = () => this.setState({ loading: false })
  
  render() {
    const { showLoading, hideLoading } = this
    
    const value ={
      ...this.state,
      showLoading,
      hideLoading
    }
    return (
      <LoadingContext.Provider value={value}>
        <LoadingContext.Consumer>
        {
          ({ showLoading, hideLoading, loading, message }) => (
            <React.Fragment>
              <ComponenteRecebendo1 {...{ showLoading, hideLoading }} />
              <ComponenteRecebendo2 {...{ showLoading, hideLoading }} />
              <Loading {...{ loading, message }} />
            </React.Fragment>
          )
        }
        </LoadingContext.Consumer>
      </LoadingContext.Provider>
    )
  }
}

Pegando os dados no componente filho:

ComponenteRecebendo1.jsx

import React, { Component } from 'react' 
 
import { getUsers } from '../services/api' 
 
class ComponenteRecebendo1 extends Component { 

    getUsers = async () => {
        // Pegando os dados aqui
        const { showLoading, hideLoading } = this.props
        showLoading('Carregando os Usuários');
        const response = await getUsers().then(res => {
            hideLoading();
            return res
        }) 
        console.log({ response }) 
    } 
 
    render() { 
        return ( 
            <button onClick={this.getUsers}>Buscar usuários</button>
        ) 
    } 
} 
 
export default Users

Componente de loading:

Loading.jsx

import React from 'react';
import Spinner from 'react-spinkit';

const Loading = ({ loading, message }) => {
    return loading ? (
        <div className='overlay-content'> 
            <div className='wrapper'> 
                <Spinner 
                    name='pacman' 
                    fadeIn='none' 
                    color='yellow' 
                /> 
                <span className='message'> 
                    {message} 
                </span> 
            </div> 
        </div> 
    ) : null
}

export default Loading
// Se atualizando
render()                      // Quando o componente reinderiza
getDerivedStateFromProps()
shoulComponentState()         // se eu retornar um false desta função, o componente nunca reinderiza
getSnapshotBeforeUpdate()
componentDidUpdate()
// ComponentDidMount()

// Desmontar
componentWillUnmount()   // Quando o component vai ser removido da DOM
componentDidCatch()      // Quando ocorre algum erro no componente

props   // Propriedades que vem de pai para filho
state   // Variáveis de estado da aplicação 

Descrição

  • Posso escrever css no typescrit/javascript

Instalando

npm i --save styled-components

Importando na class

import styled from 'styled-components'

Usando

const Cabecalho = style.h1`
  font-size: 1.5em;
  text-align: end;
  ::after {
    content: 'peseudo-elemento';
  }
  &:hover {
    background-color: red;
    transition: 0.4s;
  }
`

const Paragrafo = style.p`
  color: #AAA;
  font-size: 1.1em;
`

render(
  <Cabecalho>
    Cabeçalho estilizado
  </Cabecalho>
  <Paragrafo>
    Parágrafo estilizado
  </Paragrafo>
)

Adaptando com condicionais

const Button = styled.button`
  background: ${props => props.proriedade1 ? "palevioletred" : "white"};
  color: ${props => props.proriedade1 ? "white" : "palevioletred"};
`;

Extendendo uma estilização

// Pegando toda estilização 'Button' e adicionando ou alterando algo
const TomatoButton = styled(Button)`
  color: tomato;
  border-color: tomato;
`;
const divCustomizada = styled('div')`
  background-color: red;
`;

Colocando a mesma estilização de uma tag em outra tag

  • Posso dar um 'parse' para outra tag;
  • Posso até mesmo passar esse estilo para um componente que eu tenha criado.
const Button = styled.button`
  background-color: red;
`
render(
  <React.Fragment>
    <Button>Um botão</Button>
    <Button as='p'>Um parágrafo</Button>
    <Button as='a' href='/'>Um link</Button>
    <Button as={UmComponentCriado}>Um componente que eu criei</Button>
  </React.Fragment>
)

Retornando o mesmo componente com 2 estilizações

const Link = ({ className, children }) => (
  <a className={className}>
    {children}
  </a>
);

const StyledLink = styled(Link)`
  color: palevioletred;
  font-weight: bold;
`;

render(
  <div>
    <Link />
    <StyledLing />
  </div>
)

Keyframes

// Criando animação
const rotate = keyframes`
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
`;

// Atribuindo animação à classe
const Rotate = styled.div`
  animation: ${rotate} 2s linear infinite;
`;

Em um componente de classe

Exemplo:

import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

const Button = ({ href, children }) => {
  return <a href={href}>{children}</a>;
};

const StyledButton = styled(Button)`
  color: palevioletred;
  font-weight: bold;
`;

Button.propTypes = {
  href: PropTypes.string,
  children: PropTypes.any
};
export default StyledButton;

Criando um projeto

typescript

npx create-react-app my-app --typescript

ou

yarn create react-app my-app --typescript

Em um projeto já criado

typescript

npm install --save typescript @types/node @types/react @types/react-dom @types/jest

scss

npm install --save node-sass

Importando arquivos de um scss para outro

@import 'styles/_colors.scss'; // assumindo que o estilo está dentro do src/
@import '~nprogress/nprogress'; // importando da pasta nprogress do node-modules
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment