Kako koristiti Redux u svojoj aplikaciji React TypeScript

Redux je predvidljivi spremnik stanja za JavaScript aplikacije. Popularna je knjižnica za upravljanje stanjem u React aplikacijama.

Redux može ponuditi bolje iskustvo za programere kada ga koristite zajedno s TypeScriptom. TypeScript je superset JavaScripta koji provjerava kôd kako bi bio robustan i razumljiv.

U ovom vodiču pokazat ću vam kako koristiti Redux u vašem React TypeScript projektu izgradnjom aplikacije koja vam omogućuje dodavanje, brisanje i prikazivanje članaka.

Uronimo.

  • Preduvjeti
  • Postavljanje
  • Stvorite vrste
  • Stvorite vrste radnji
  • Stvorite kreatore radnji
  • Stvorite reduktor
  • Stvorite trgovinu
  • Stvorite komponente

Preduvjeti

Ovaj tutorijal pretpostavlja da barem osnovno razumijete React, Redux i TypeScript.

Dakle, ako niste upoznati s ovim tehnologijama, prvo pokušajte pročitati ovaj praktični vodič za TypeScript ili ovaj udžbenik React Redux. Inače, krenimo.

Postavljanje projekta

Da bismo koristili Redux i TypeScript, moramo stvoriti novu React aplikaciju.

Da bismo to učinili, otvorimo CLI (sučelje naredbenog retka) i izvršimo ovu naredbu:

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

Dalje, strukturirajmo projekt na sljedeći način:

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

Datotečna struktura projekta prilično je jednostavna. Međutim, valja napomenuti dvije stvari:

  • storeMapa koja sadrži datoteke vezane uz reagirati Redux.
  • type.d.tsDatoteka koja sadrži vrste pisaćim strojem, koji se sada može koristiti u drugim datotekama bez uvoza.

Međutim, sada možemo instalirati Redux i stvoriti našu prvu trgovinu.

Otvorimo projekt i pokrenimo sljedeću naredbu:

 yarn add redux react-redux redux-thunk 

Ili prilikom korištenja npm

 npm install redux react-redux redux-thunk 

Također moramo instalirati njihove tipove kao razvojne ovisnosti kako bismo Typescripu pomogli da razumije knjižnice.

Dakle, izvršimo ovu naredbu ponovno na CLI.

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

Ili za npm:

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

Sjajno! Ovim korakom naprijed, sada možemo stvoriti TypeScript vrste za projekt u sljedećem odjeljku.

Stvorite vrste

Tipovi TypeScript omogućuju vam postavljanje tipova za svoje varijable, parametre funkcije itd.

  • vrsta.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 

Ovdje započinjemo deklariranjem sučelja IArticlekoje odražava oblik određenog članka.

Zatim, imamo ArticleState, ArticleActioni DispatchTypekoja će poslužiti kao vrsta za, odnosno, država objekt, akcijske kreatori, a funkcija slanja pruža Redux.

Međutim, sada imamo potrebne tipove za početak korištenja React Redux-a. Stvorimo vrste radnji.

Stvorite vrste radnji

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

Za trgovinu Redux trebaju nam dvije vrste radnji. Jedan za dodavanje članaka i drugi za brisanje.

Stvorite kreatore radnji

  • 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) } } 

U ovom uputstvu simulirat ću HTTP zahtjev odgađajući ga za 0,5 sekundi. Ali, slobodno upotrijebite pravi poslužitelj ako želite.

Ovdje će funkcija addArticleposlati akciju za dodavanje novog članka, a metoda removeArticleće učiniti suprotno. Zato izbrišite objekt prosljeđen kao argument.

Stvorite reduktor

Reduktor je čista funkcija koja prima stanje spremišta i radnju kao parametre, a zatim vraća ažurirano stanje.

  • spremište / reduktor.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", }, ], } 

Kao što ovdje možete vidjeti, proglašavamo početno stanje da bi se neki članci mogli prikazati kada se stranica učita. Objekt stanja mora odgovarati tipu ArticleState- u suprotnom, TypeScript će izbaciti pogrešku.

  • spremište / reduktor.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-preview

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

You can find the finished project in this CodeSandbox.

You can find other great content like this on my blog or follow me on Twitter to get notified.

Thanks for reading.