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.