A Redux használata a React TypeScript alkalmazásban

A Redux egy kiszámítható állapotú tároló a JavaScript-alkalmazásokhoz. Ez egy népszerű könyvtár az állapot kezelésére a React alkalmazásokban.

A Redux jobb fejlesztői élményt kínál, ha a TypeScript-szel együtt használja. A TypeScript a JavaScript egy olyan halmaza, amely típusellenőrzi a kódot, hogy robusztus és érthető legyen.

Ebben az útmutatóban megmutatom, hogyan használhatja a Redux-ot a React TypeScript projektben egy olyan alkalmazás létrehozásával, amely lehetővé teszi cikkek hozzáadását, törlését és megjelenítését.

Merüljünk be.

  • Előfeltételek
  • Felállítása
  • Hozza létre a típusokat
  • Hozza létre a művelettípusokat
  • Hozza létre az akciókészítőket
  • Hozzon létre egy reduktort
  • Hozzon létre egy üzletet
  • Hozza létre az összetevőket

Előfeltételek

Ez az oktatóanyag feltételezi, hogy legalább alaposan ismeri a React, a Redux és a TypeScript ismereteit.

Tehát, ha még nem ismeri ezeket a technológiákat, először próbálja meg elolvasni ezt a gyakorlati útmutatót a TypeScript-hez vagy ezt a React Redux oktatóanyagot. Ellenkező esetben kezdjük.

A projekt beállítása

A Redux és a TypeScript használatához létre kell hoznunk egy új React alkalmazást.

Ehhez nyissuk meg a CLI-t (parancssori felület), és hajtsuk végre ezt a parancsot:

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

Ezután strukturáljuk a projektet az alábbiak szerint:

├── 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 projekt fájlszerkezete meglehetősen egyszerű. Két dolgot kell azonban megjegyezni:

  • A storeReact Redux fájlhoz kapcsolódó fájlokat tartalmazó mappa.
  • A type.d.tsTypeScript típusokat tartalmazó fájl, amelyet importálás nélkül más fájlokban is fel lehet használni.

Ez azt jelenti, hogy most telepíthetjük a Redux-et és létrehozhatjuk az első üzletünket.

Tehát nyissuk meg a projektet, és futtassuk a következő parancsot:

 yarn add redux react-redux redux-thunk 

Vagy használatakor npm

 npm install redux react-redux redux-thunk 

A típusokat fejlesztési függőségként is telepítenünk kell, hogy a TypeScript megértsék a könyvtárakat.

Tehát hajtsuk végre újra ezt a parancsot a CLI-n.

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

Vagy npm:

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

Nagy! Ezzel az előrelépéssel most létrehozhatjuk a TypeScript típusokat a projekthez a következő szakaszban.

Hozza létre a típusokat

A TypeScript típusok lehetővé teszik a változók, a funkcióparaméterek stb. Típusainak beállítását.

  • típus.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 

Itt kezdjük az interfész deklarálásával, IArticleamely tükrözi az adott cikk alakját.

Ezután megvan a ArticleState, ArticleActionés DispatchTypeez a Redux által biztosított állapotobjektum, az akciókészítők és a diszpécser függvény típusaként szolgál.

Ez azt jelenti, hogy megvan a szükséges típus a React Redux használatának megkezdéséhez. Hozzuk létre a művelettípusokat.

Hozza létre a művelettípusokat

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

Két művelettípusra van szükségünk a Redux áruházhoz. Az egyik cikkek hozzáadásához, a másik pedig törléshez.

Hozza létre az akciókészítőket

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

Ebben az oktatóanyagban szimulálom a HTTP kérést úgy, hogy késleltetem 0,5 másodpercig. De nyugodtan használjon valódi szervert, ha akarja.

Itt a függvény addArticleműveletet küld egy új cikk hozzáadásához, és a módszer removeArticleennek ellenkezőjét fogja tenni. Tehát törölje az argumentumként átadott objektumot.

Hozzon létre egy reduktort

A reduktor egy tiszta függvény, amely paraméterként fogadja a tár és egy művelet állapotát, majd visszaadja a frissített állapotot.

  • bolt / 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", }, ], } 

Amint itt láthatja, deklarálunk egy kezdeti állapotot, hogy néhány cikk megjelenjen az oldal betöltésekor. Az állapotobjektumnak meg kell egyeznie a típussal ArticleState- ellenkező esetben a TypeScript hibát dob.

  • bolt / 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.