Πώς να χρησιμοποιήσετε το Redux στην εφαρμογή React TypeScript

Το Redux είναι ένα προβλέψιμο κοντέινερ κατάστασης για εφαρμογές JavaScript. Είναι μια δημοφιλής βιβλιοθήκη για τη διαχείριση της κατάστασης στις εφαρμογές React.

Το Redux μπορεί να προσφέρει μια καλύτερη εμπειρία προγραμματιστή όταν το χρησιμοποιείτε μαζί με το TypeScript. Το TypeScript είναι ένα υπερσύνολο JavaScript που πληκτρολογεί τον κώδικα για να τον κάνει ισχυρό και κατανοητό.

Σε αυτόν τον οδηγό, θα σας δείξω πώς να χρησιμοποιήσετε το Redux στο έργο React TypeScript δημιουργώντας μια εφαρμογή που σας επιτρέπει να προσθέσετε, να διαγράψετε και να εμφανίσετε άρθρα.

Ας βουτήξουμε.

  • Προαπαιτούμενα
  • Εγκαθιστώ
  • Δημιουργήστε τους τύπους
  • Δημιουργήστε τους τύπους ενεργειών
  • Δημιουργήστε τους δημιουργούς δράσης
  • Δημιουργήστε έναν μειωτήρα
  • Δημιουργήστε ένα κατάστημα
  • Δημιουργήστε τα στοιχεία

Προαπαιτούμενα

Αυτό το σεμινάριο προϋποθέτει ότι έχετε τουλάχιστον μια βασική κατανόηση των React, Redux και TypeScript.

Επομένως, εάν δεν είστε εξοικειωμένοι με αυτές τις τεχνολογίες, δοκιμάστε πρώτα να διαβάσετε αυτόν τον πρακτικό οδηγό για το TypeScript ή αυτόν τον οδηγό React Redux. Διαφορετικά, ας ξεκινήσουμε.

Εγκατάσταση του έργου

Για να χρησιμοποιήσουμε το Redux και το TypeScript, πρέπει να δημιουργήσουμε μια νέα εφαρμογή React.

Για να το κάνουμε αυτό, ας ανοίξουμε το CLI (διεπαφή γραμμής εντολών) και να εκτελέσουμε αυτήν την εντολή:

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

Στη συνέχεια, ας δομήσουμε το έργο ως εξής:

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

Η δομή αρχείων του έργου είναι αρκετά απλή. Ωστόσο, υπάρχουν δύο πράγματα που πρέπει να σημειώσετε:

  • Ο storeφάκελος που περιέχει αρχεία που σχετίζονται με το React Redux.
  • Το type.d.tsαρχείο που περιέχει τους τύπους TypeScript, τα οποία μπορούν να χρησιμοποιηθούν τώρα σε άλλα αρχεία χωρίς εισαγωγή.

Τούτου λεχθέντος, μπορούμε τώρα να εγκαταστήσουμε το Redux και να δημιουργήσουμε το πρώτο μας κατάστημα.

Ας ανοίξουμε λοιπόν το έργο και εκτελέστε την ακόλουθη εντολή:

 yarn add redux react-redux redux-thunk 

Ή κατά τη χρήση npm

 npm install redux react-redux redux-thunk 

Πρέπει επίσης να εγκαταστήσουμε τους τύπους τους ως εξαρτήσεις ανάπτυξης για να βοηθήσουμε το TypeScript να κατανοήσει τις βιβλιοθήκες.

Ας εκτελέσουμε ξανά αυτήν την εντολή στο CLI

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

Ή για npm:

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

Μεγάλος! Με αυτό το βήμα προς τα εμπρός, μπορούμε τώρα να δημιουργήσουμε τους τύπους TypeScript για το έργο στην επόμενη ενότητα.

Δημιουργήστε τους τύπους

Οι τύποι TypeScript σάς επιτρέπουν να ορίσετε τύπους για τις μεταβλητές σας, τις παραμέτρους λειτουργίας και ούτω καθεξής.

  • 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 

Εδώ, ξεκινάμε δηλώνοντας τη διεπαφή IArticleπου αντικατοπτρίζει το σχήμα ενός δεδομένου άρθρου.

Στη συνέχεια, έχουμε ArticleState, ArticleActionκαι DispatchTypeότι θα χρησιμεύσει ως είδη για, αντίστοιχα, το αντικείμενο κράτος, οι δημιουργοί δράση, και η λειτουργία αποστολής που παρέχεται από Redux.

Τούτου λεχθέντος, έχουμε τώρα τους απαραίτητους τύπους για να αρχίσουμε να χρησιμοποιούμε το React Redux. Ας δημιουργήσουμε τους τύπους δράσης.

Δημιουργήστε τους τύπους ενεργειών

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

Χρειαζόμαστε δύο τύπους δράσης για το κατάστημα Redux. Ένα για την προσθήκη άρθρων και ένα άλλο για διαγραφή.

Δημιουργήστε τους δημιουργούς δράσης

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

Σε αυτό το σεμινάριο, θα προσομοιώσω το αίτημα HTTP καθυστερώντας το για 0,5 δευτερόλεπτα. Αλλά, μπορείτε να χρησιμοποιήσετε έναν πραγματικό διακομιστή εάν θέλετε.

Εδώ, η συνάρτηση addArticleθα αποστείλει μια ενέργεια για την προσθήκη ενός νέου άρθρου και η μέθοδος removeArticleθα κάνει το αντίθετο. Διαγράψτε λοιπόν το αντικείμενο που μεταβιβάστηκε ως όρισμα.

Δημιουργήστε έναν μειωτήρα

Ένας μειωτής είναι μια καθαρή συνάρτηση που λαμβάνει την κατάσταση του καταστήματος και μια ενέργεια ως παραμέτρους και στη συνέχεια επιστρέφει την ενημερωμένη κατάσταση.

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

Όπως μπορείτε να δείτε εδώ, δηλώνουμε μια αρχική κατάσταση για την εμφάνιση ορισμένων άρθρων κατά τη φόρτωση της σελίδας. Το αντικείμενο κατάστασης πρέπει να ταιριάζει με τον τύπο ArticleState- διαφορετικά, το TypeScript θα ρίξει ένα σφάλμα.

  • store / 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:

προεπισκόπηση εφαρμογής

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

Μπορείτε να βρείτε το ολοκληρωμένο έργο σε αυτό το CodeSandbox.

Μπορείτε να βρείτε άλλο υπέροχο περιεχόμενο όπως αυτό στο ιστολόγιό μου ή να με ακολουθήσετε στο Twitter για να ενημερωθείτε.

Ευχαριστώ για την ανάγνωση.