Como usar o Redux em seu aplicativo React TypeScript

Como usar o Redux em seu aplicativo React TypeScript

8 de September, 2020 0 By António César de Andrade


Redux é um contêiner de estado previsível para aplicativos JavaScript. É uma biblioteca popular para gerenciamento de estado em aplicativos React.

Redux pode oferecer uma melhor experiência de desenvolvedor quando você o usa junto com o TypeScript. TypeScript é um superconjunto de JavaScript que verifica o tipo do código para torná-lo robusto e compreensível.

Neste guia, mostrarei como usar o Redux em seu projeto React TypeScript ao construir um aplicativo que permite adicionar, excluir e mostrar artigos.

Vamos mergulhar.

Pré-requisitos

Este tutorial presume que você tenha pelo menos um conhecimento básico de React, Redux e TypeScript.

Então, se você não está familiarizado com essas tecnologias, primeiro tente ler este guia prático para TypeScript ou este tutorial do React Redux. Caso contrário, vamos começar.

Configurando o projeto

Para usar Redux e TypeScript, precisamos criar um novo aplicativo React.

Para isso, vamos abrir a CLI (interface da linha de comando) e executar este comando:

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

A seguir, vamos estruturar o projeto da seguinte maneira:

├── src
|  ├── components
|  |  ├── AddArticle.tsx
|  |  └── Article.tsx
|  ├── store
|  |  ├── actionCreators.ts
|  |  ├── actionTypes.ts
|  |  └── reducer.ts
|  ├── type.d.ts
|  ├── App.test.tsx
|  ├── App.tsx
|  ├── index.css
|  ├── index.tsx
|  ├── react-app-env.d.ts
|  └── setupTests.ts
├── tsconfig.json
├── package.json
└── yarn.lock

A estrutura de arquivos do projeto é bastante simples. No entanto, há duas coisas a serem observadas:

  • o store pasta que contém arquivos relacionados ao React Redux.
  • o type.d.ts arquivo que contém os tipos TypeScript, que podem ser usados ​​agora em outros arquivos sem importação.

Dito isso, agora podemos instalar o Redux e criar nossa primeira loja.

Então, vamos abrir o projeto e executar o seguinte comando:

  yarn add redux react-redux redux-thunk

Ou ao usar npm

  npm install redux react-redux redux-thunk

Também temos que instalar seus tipos como dependências de desenvolvimento para ajudar o TypeScript a entender as bibliotecas.

Então, vamos executar este comando novamente na CLI.

  yarn add -D @types/redux @types/react-redux @types/redux-thunk

Ou para npm:

  npm install -D @types/redux @types/react-redux @types/redux-thunk

Ótimo! Com este passo adiante, podemos agora criar os tipos TypeScript para o projeto na próxima seção.

Crie os tipos

Os tipos de TypeScript permitem definir tipos para suas variáveis, parâmetros de função e assim por diante.

interface IArticle {
  id: number
  title: string
  body: string
}

type ArticleState = {
  articles: IArticle[]
}

type ArticleAction = {
  type: string
  article: IArticle
}

type DispatchType = (args: ArticleAction) => ArticleAction

Aqui, começamos declarando a interface IArticle que reflete a forma de um determinado artigo.

Então nós temos ArticleState, ArticleAction, e DispatchType que servirão como tipos para, respectivamente, o objeto de estado, os criadores de ação e a função de despacho fornecida por Redux.

Dito isso, agora temos os tipos necessários para começar a usar o React Redux. Vamos criar os tipos de ação.

Crie os tipos de ação

export const ADD_ARTICLE = "ADD_ARTICLE"
export const REMOVE_ARTICLE = "REMOVE_ARTICLE"

Precisamos de dois tipos de ação para a loja Redux. Um para adicionar artigos e outro para excluir.

Crie os criadores de ação

import * as actionTypes from "./actionTypes"

export function addArticle(article: IArticle) {
  const action: ArticleAction = {
    type: actionTypes.ADD_ARTICLE,
    article,
  }

  return simulateHttpRequest(action)
}

export function removeArticle(article: IArticle) {
  const action: ArticleAction = {
    type: actionTypes.REMOVE_ARTICLE,
    article,
  }
  return simulateHttpRequest(action)
}

export function simulateHttpRequest(action: ArticleAction) {
  return (dispatch: DispatchType) => {
    setTimeout(() => {
      dispatch(action)
    }, 500)
  }
}

Neste tutorial, simularei a solicitação HTTP atrasando-a por 0,5 segundos. Mas fique à vontade para usar um servidor real se quiser.

Aqui, a função addArticle irá despachar uma ação para adicionar um novo artigo, e o método removeArticle fará o oposto. Portanto, exclua o objeto passado como argumento.

Crie um redutor

Um redutor é uma função pura que recebe o estado da loja e uma ação como parâmetros e então retorna o estado atualizado.

import * as actionTypes from "./actionTypes"

const initialState: ArticleState = {
  articles: [
    {
      id: 1,
      title: "post 1",
      body:
        "Quisque cursus, metus vitae pharetra Nam libero tempore, cum soluta nobis est eligendi",
    },
    {
      id: 2,
      title: "post 2",
      body:
        "Harum quidem rerum facilis est et expedita distinctio quas molestias excepturi sint",
    },
  ],
}

Como você pode ver aqui, declaramos um estado inicial para ter alguns artigos para mostrar quando a página carregar. O objeto de estado precisa corresponder ao tipo ArticleState – caso contrário, o TypeScript gerará um erro.

const reducer = (
  state: ArticleState = initialState,
  action: ArticleAction
): ArticleState => {
  switch (action.type) {
    case actionTypes.ADD_ARTICLE:
      const newArticle: IArticle = {
        id: Math.random(), // not really unique
        title: action.article.title,
        body: action.article.body,
      }
      return {
        ...state,
        articles: state.articles.concat(newArticle),
      }
    case actionTypes.REMOVE_ARTICLE:
      const updatedArticles: IArticle[] = state.articles.filter(
        article => article.id !== action.article.id
      )
      return {
        ...state,
        articles: updatedArticles,
      }
  }
  return state
}

export default reducer

Em seguida, temos o reducer função que espera o estado anterior e uma ação para poder atualizar a loja. Aqui, temos duas ações: uma para adicionar e outra para excluir.

Com isso no lugar, agora podemos lidar com o estado com o redutor. Vamos agora criar uma loja para o projeto.

Crie uma loja

Uma loja Redux é onde mora o estado do seu aplicativo.

import * as React from "react"
import { render } from "react-dom"
import { createStore, applyMiddleware, Store } from "redux"
import { Provider } from "react-redux"
import thunk from "redux-thunk"

import App from "./App"
import reducer from "./store/reducer"

const store: Store<ArticleState, ArticleAction> & {
  dispatch: DispatchType
} = createStore(reducer, applyMiddleware(thunk))

const rootElement = document.getElementById("root")
render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
)

Como você pode ver, importamos a função redutora e a passamos como um argumento para o método createStore para criar uma nova loja Redux. o redux-thunk O middleware precisa ser seguido como um segundo parâmetro, bem como o método para ser capaz de lidar com o código assíncrono.

Em seguida, conectamos o React ao Redux, fornecendo o store objeto como adereços para o Provider componente.

Agora podemos usar Redux neste projeto e acessar a loja. Portanto, vamos criar os componentes para obter e manipular os dados.

Crie os componentes

  • componentes / AddArticle.tsx

import * as React from "react"

type Props = {
  saveArticle: (article: IArticle | any) => void
}

export const AddArticle: React.FC<Props> = ({ saveArticle }) => {
  const [article, setArticle] = React.useState<IArticle | {}>()

  const handleArticleData = (e: React.FormEvent<HTMLInputElement>) => {
    setArticle({
      ...article,
      [e.currentTarget.id]: e.currentTarget.value,
    })
  }

  const addNewArticle = (e: React.FormEvent) => {
    e.preventDefault()
    saveArticle(article)
  }

  return (
    <form onSubmit={addNewArticle} className="Add-article">
      <input
        type="text"
        id="title"
        placeholder="Title"
        onChange={handleArticleData}
      />
      <input
        type="text"
        id="body"
        placeholder="Description"
        onChange={handleArticleData}
      />
      <button disabled={article === undefined ? true : false}>
        Add article
      </button>
    </form>
  )
}

Para adicionar um novo artigo, usaremos este componente de formulário. Recebe a função saveArticle como parâmetro, que permite adicionar um novo artigo à loja.

O objeto do artigo deve seguir o tipo IArticle para deixar o TypeScript feliz.

import * as React from "react"
import { Dispatch } from "redux"
import { useDispatch } from "react-redux"

type Props = {
  article: IArticle
  removeArticle: (article: IArticle) => void
}

export const Article: React.FC<Props> = ({ article, removeArticle }) => {
  const dispatch: Dispatch<any> = useDispatch()

  const deleteArticle = React.useCallback(
    (article: IArticle) => dispatch(removeArticle(article)),
    [dispatch, removeArticle]
  )

  return (
    <div className="Article">
      <div>
        <h1>{article.title}</h1>
        <p>{article.body}</p>
      </div>
      <button onClick={() => deleteArticle(article)}>Delete</button>
    </div>
  )
}

o Article componente mostra um objeto de artigo.

A função removeArticle tem que despachar para acessar a loja e, portanto, excluir um determinado artigo. Essa é a razão pela qual usamos o useDispatch gancho aqui, que permite Redux completar a ação de remoção.

Em seguida, o uso de useCallback ajuda a evitar uma nova renderização desnecessária, memorizando os valores como dependências.

Finalmente temos os componentes de que precisamos para adicionar e mostrar os artigos. Vamos agora adicionar a última peça ao quebra-cabeça usando-as no App.tsx Arquivo.

import * as React from "react"
import { useSelector, shallowEqual, useDispatch } from "react-redux"
import "./styles.css"

import { Article } from "./components/Article"
import { AddArticle } from "./components/AddArticle"
import { addArticle, removeArticle } from "./store/actionCreators"
import { Dispatch } from "redux"

const App: React.FC = () => {
  const articles: readonly IArticle[] = useSelector(
    (state: ArticleState) => state.articles,
    shallowEqual
  )

  const dispatch: Dispatch<any> = useDispatch()

  const saveArticle = React.useCallback(
    (article: IArticle) => dispatch(addArticle(article)),
    [dispatch]
  )

  return (
    <main>
      <h1>My Articles</h1>
      <AddArticle saveArticle={saveArticle} />
      {articles.map((article: IArticle) => (
        <Article
          key={article.id}
          article={article}
          removeArticle={removeArticle}
        />
      ))}
    </main>
  )
}

export default App

o useSelector gancho permite o acesso ao estado da loja. Aqui passamos shallowEqual como um segundo argumento para o método para dizer ao Redux para usar igualdade superficial ao verificar as alterações.

Em seguida, contamos com useDispatch para despachar uma ação para adicionar artigos na loja. Por fim, percorremos a matriz de artigos e passamos cada um para o Article componente para mostrá-lo.

Com isso, agora podemos navegar até a raiz do projeto e, em seguida, executar este comando:

  yarn start

Ou para npm:

  npm start

Se você abrir http://localhost:3000/ no navegador, você verá o seguinte:

app-preview

Ótimo! Nosso aplicativo parece bom. Com isso, terminamos de usar o Redux em um aplicativo React TypeScript.

Você pode encontrar o projeto concluído neste CodeSandbox.

Você pode encontrar outro ótimo conteúdo como este em meu blog ou me segue no Twitter para ser notificado.

Obrigado pela leitura.





Fonte

Click to rate this post!
[Total: 0 Average: 0]