Sådan bruges Redux i din React TypeScript-app

Redux er en forudsigelig tilstandsbeholder til JavaScript-apps. Det er et populært bibliotek til administration af tilstand i React-apps.

Redux kan tilbyde en bedre udvikleroplevelse, når du bruger den sammen med TypeScript. TypeScript er et supersæt af JavaScript, der typechecker kode for at gøre den robust og forståelig.

I denne vejledning vil jeg vise dig, hvordan du bruger Redux i dit React TypeScript-projekt ved at oprette en app, der giver dig mulighed for at tilføje, slette og vise artikler.

Lad os dykke ind.

  • Forudsætninger
  • Sætte op
  • Opret typerne
  • Opret handlingstyperne
  • Opret handlingsskaberne
  • Opret en reducering
  • Opret en butik
  • Opret komponenterne

Forudsætninger

Denne vejledning forudsætter, at du i det mindste har en grundlæggende forståelse af React, Redux og TypeScript.

Så hvis du ikke er fortrolig med disse teknologier, skal du først prøve at læse denne praktiske vejledning til TypeScript eller denne React Redux-tutorial. Ellers lad os komme i gang.

Opsætning af projektet

For at bruge Redux og TypeScript er vi nødt til at oprette en ny React-app.

Lad os åbne CLI (kommandolinjegrænseflade) og udføre denne kommando:

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

Lad os derefter strukturere projektet som følger:

├── 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 

Projektets filstruktur er ret enkel. Der er dog to ting at bemærke:

  • Den storemappe, der indeholder filer relateret til Reagere Redux.
  • Den type.d.tsfil, der indeholder TypeScript-typerne, som nu kan bruges i andre filer uden import.

Når det er sagt, kan vi nu installere Redux og oprette vores allerførste butik.

Så lad os åbne projektet og køre følgende kommando:

 yarn add redux react-redux redux-thunk 

Eller når du bruger npm

 npm install redux react-redux redux-thunk 

Vi er også nødt til at installere deres typer som udviklingsafhængigheder for at hjælpe TypeScript med at forstå bibliotekerne.

Så lad os udføre denne kommando igen på CLI.

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

Eller til npm:

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

Store! Med dette skridt fremad kan vi nu oprette TypeScript-typerne til projektet i næste afsnit.

Opret typerne

TypeScript-typer giver dig mulighed for at indstille typer til dine variabler, funktionsparametre osv.

  • type.d.ts
interface IArticle { id: number title: string body: string } type ArticleState = { articles: IArticle[] } type ArticleAction = { type: string article: IArticle } type DispatchType = (args: ArticleAction) => ArticleAction 

Her starter vi med at erklære grænsefladen, IArticleder afspejler formen på en given artikel.

Så har vi ArticleState, ArticleActionog DispatchTypeder vil tjene som typer for henholdsvis staten objekt, handlingen skabere, og afsendelse funktion fra Redux.

Når det er sagt, har vi nu de nødvendige typer for at begynde at bruge React Redux. Lad os oprette handlingstyperne.

Opret handlingstyperne

  • store / actionTypes.ts
export const ADD_ARTICLE = "ADD_ARTICLE" export const REMOVE_ARTICLE = "REMOVE_ARTICLE" 

Vi har brug for to handlingstyper til Redux-butikken. Én til tilføjelse af artikler og en anden til sletning.

Opret handlingsskaberne

  • store / actionCreators.ts
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) } } 

I denne vejledning simulerer jeg HTTP-anmodningen ved at forsinke den i 0,5 sekunder. Men du er velkommen til at bruge en rigtig server, hvis du vil.

Her sender funktionen addArticleen handling for at tilføje en ny artikel, og metoden removeArticlegør det modsatte. Så slet det objekt, der er sendt ind som et argument.

Opret en reducering

En reducering er en ren funktion, der modtager butikstilstanden og en handling som parametre og derefter returnerer den opdaterede tilstand.

  • butik / reducer.ts
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", }, ], } 

Som du kan se her, erklærer vi, at en indledende tilstand har nogle artikler, der skal vises, når siden indlæses. Statens objekt skal matche typen ArticleState- ellers kaster TypeScript en fejl.

  • butik / reducer.ts
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 

Next, we have the reducer function that expects the previous state and an action to be able to update the store. Here, we have two actions: one for adding and another for deleting.

With that in place, we can now handle the state with the reducer. Let's now create a store for the project.

Create a store

A Redux store is where your app's state lives.

  • index.tsx
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 & { dispatch: DispatchType } = createStore(reducer, applyMiddleware(thunk)) const rootElement = document.getElementById("root") render(   , rootElement ) 

As you can see, we import the reducer function and then pass it as an argument to the method createStore in order to create a new Redux store. The redux-thunk middleware needs to be proceeded as a second parameter as well to the method to be able to handle asynchronous code.

Next, we connect React to Redux by providing the store object as props to the Provider component.

We can now use Redux in this project and access the store. So, let's create the components to get and manipulate the data.

Create the components

  • components/AddArticle.tsx
import * as React from "react" type Props =  saveArticle: (article: IArticle  export const AddArticle: React.FC = ({ saveArticle }) => { const [article, setArticle] = React.useState() const handleArticleData = (e: React.FormEvent) => { setArticle({ ...article, [e.currentTarget.id]: e.currentTarget.value, }) } const addNewArticle = (e: React.FormEvent) => { e.preventDefault() saveArticle(article) } return (     Add article   ) } 

To add a new article, we will be using this form component. It receives the function saveArticle as a parameter, which allows adding a new article to the store.

The article object should follow the type IArticle to make TypeScript happy.

  • components/Article.tsx
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 = ({ article, removeArticle }) => { const dispatch: Dispatch = useDispatch() const deleteArticle = React.useCallback( (article: IArticle) => dispatch(removeArticle(article)), [dispatch, removeArticle] ) return ( 

{article.title}

{article.body}

deleteArticle(article)}>Delete ) }

The Article component shows an article object.

The function removeArticle has to dispatch to access the store and hence delete a given article. That's the reason we use the useDispatch hook here, which lets Redux complete the removing action.

Next, the use of useCallback helps to avoid unnecessary re-rendering by memoizing values as dependencies.

We finally have the components we need to add and show the articles. Let's now add the last piece to the puzzle by using them in the App.tsx file.

  • App.tsx
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 = useDispatch() const saveArticle = React.useCallback( (article: IArticle) => dispatch(addArticle(article)), [dispatch] ) return (  

My Articles

{articles.map((article: IArticle) => ( ))} ) } export default App

The useSelector hook enables access to the state of the store. Here, we pass shallowEqual as a second argument to the method to tell to Redux to use shallow equality when checking for changes.

Next, we rely on useDispatch to dispatch an action for adding articles in the store. Finally, we loop through the array of articles and pass each to the Article component to show it.

With that, we can now browse to the root of the project and then execute this command:

 yarn start 

Or for npm:

 npm start 

If you open //localhost:3000/ in the browser, you should see this:

app-forhåndsvisning

Great! Our app looks good. With this, we have now finished using Redux in a React TypeScript app.

Du kan finde det færdige projekt i denne CodeSandbox.

Du kan finde andet godt indhold som dette på min blog eller følge mig på Twitter for at få besked.

Tak for læsningen.