Standardmäßig werden die Aktionen von Redux synchron versendet, was ein Problem für jede nicht-triviale Anwendung ist, die mit einer externen API kommunizieren muss oder Nebenwirkungen ausführt. Redux ermöglicht auch Middleware, die zwischen dem Versand einer Aktion und dem Eintreffen der Aktion bei den Reduzierern angesiedelt ist.
Es gibt zwei sehr beliebte Middleware-Bibliotheken, die Nebenwirkungen und asynchrone Aktionen ermöglichen: Redux Thunk und Redux Saga. In diesem Beitrag erkunden Sie Redux Thunk.
Thunk ist ein Programmierkonzept, bei dem eine Funktion verwendet wird, um die Bewertung/Berechnung einer Aktion zu verzögern.
Redux Thunk ist eine Middleware, mit der Sie Aktionserzeuger aufrufen können, die anstelle eines Aktionsobjekts eine Funktion zurückgeben. Diese Funktion empfängt die Versandmethode des Speichers, die dann verwendet wird, um regelmäßige synchrone Aktionen innerhalb des Funktionskörpers zu versenden, sobald die asynchronen Operationen abgeschlossen sind.
In diesem Artikel lernen Sie, wie Sie Redux Thunk hinzufügen und wie es in eine hypothetischen Todo-Anwendung passen kann.
Dieser Beitrag geht davon aus, dass Sie einige grundlegende Kenntnisse von React und Redux haben. Wenn Sie mit Redux beginnen, können Sie auf diesen Beitrag verweisen.
Dieses Tutorial baut auf einer hypothetischen Todo-Anwendung auf, die zu erledigende und abgeschlossene Tasks verfolgt. Wir gehen davon aus, dass create-react-app
verwendet wurde, um eine neue React-Anwendung zu generieren, und redux
, react-redux
und axios
bereits installiert sind.
Die genaueren Details, wie man eine Todo-Anwendung von Grund auf neu erstellt, werden hier nicht erläutert. Es wird als konzeptioneller Rahmen für die Hervorhebung von Redux Thunk präsentiert.
redux-thunk
Verwenden Sie zunächst das Terminal, um zum Projektverzeichnis zu navigieren und das redux-thunk
Paket in Ihrem Projekt zu installieren:
- npm install redux-thunk@2.3.0
Anmerkung: Redux Thunk besteht nur aus 14 Zeilen Code. Sehen Sie sich die Quelle hier an, um zu erfahren, wie eine Redux Middleware unter der Oberfläche funktioniert.
Verwenden Sie nun die Middleware bei der Erstellung Ihres App-Stores mit der Anwendung von Redux applyMiddleware
. Angesichts einer React-Anwendung mit redux
und react-redux
sieht Ihre Datei index.js
wie folgt aus:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import './index.css';
import rootReducer from './reducers';
import App from './App';
import * as serviceWorker from './serviceWorker';
// use applyMiddleware to add the thunk middleware to the store
const store = createStore(rootReducer, applyMiddleware(thunk));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Jetzt wird Redux Thunk in Ihre Anwendung importiert und angewendet.
Der häufigste Anwendungsfall für Redux Thunk ist die asynchrone Kommunikation mit einer externen API zum Abrufen oder Speichern von Daten. Mit Redux Thunk ist es einfach, Aktionen, die dem Lebenszyklus einer Anforderung folgen, an eine externe API zu senden.
Bei der Erstellung eines neuen ToDo-Elements wird normalerweise zuerst eine Aktion gesendet, um anzuzeigen, dass die Erstellung eines ToDo-Elements begonnen hat. Wenn dann das ToDo-Element erfolgreich erstellt und vom externen Server zurückgegeben wird, senden Sie eine weitere Aktion mit dem neuen ToDo-Element. Für den Fall, dass ein Fehler auftritt und das ToDo nicht auf dem Server gespeichert werden kann, kann stattdessen eine Aktion mit dem Fehler versendet werden.
Sehen wir uns an, wie dies mit Redux Thunk erreicht werden kann.
Importieren Sie in Ihrer Container-Komponente die Aktion und versenden Sie diese:
import { connect } from 'react-redux';
import { addTodo } from '../actions';
import NewTodo from '../components/NewTodo';
const mapDispatchToProps = dispatch => {
return {
onAddTodo: todo => {
dispatch(addTodo(todo));
}
};
};
export default connect(
null,
mapDispatchToProps
)(NewTodo);
Die Aktion verwendet Axios um eine POST
-Anfrage an den Endpunkt bei JSONPlaceholder zu senden (https://jsonplaceholder.typicode.com/todos
):
import {
ADD_TODO_SUCCESS,
ADD_TODO_FAILURE,
ADD_TODO_STARTED,
DELETE_TODO
} from './types';
import axios from 'axios';
export const addTodo = ({ title, userId }) => {
return dispatch => {
dispatch(addTodoStarted());
axios
.post(`https://jsonplaceholder.typicode.com/todos`, {
title,
userId,
completed: false
})
.then(res => {
dispatch(addTodoSuccess(res.data));
})
.catch(err => {
dispatch(addTodoFailure(err.message));
});
};
};
const addTodoSuccess = todo => ({
type: ADD_TODO_SUCCESS,
payload: {
...todo
}
});
const addTodoStarted = () => ({
type: ADD_TODO_STARTED
});
const addTodoFailure = error => ({
type: ADD_TODO_FAILURE,
payload: {
error
}
});
Beachten Sie, wie der AddTodo
-Aktionserzeuger anstelle des regulären Aktionsobjekts eine Funktion zurückgibt. Diese Funktion empfängt die Versandmethode aus dem Store.
Innerhalb des Funktionskörpers versenden Sie zunächst eine sofortige synchrone Aktion an den Store, um anzuzeigen, dass Sie begonnen haben, das Todo mit der externen API zu speichern. Dann stellen Sie die aktuelle POST
-Anfrage mit Axios an den Server her. Bei einer erfolgreichen Antwort vom Server senden Sie eine synchrone Erfolgsaktion mit den von der Antwort empfangenen Daten, bei einer fehlgeschlagenen Antwort senden wir jedoch eine andere synchrone Aktion mit der Fehlermeldung.
Bei Verwendung einer externen API, wie in diesem Fall JSONPlaceholder, ist es möglich, die tatsächliche Netzwerkverzögerung zu sehen. Wenn Sie jedoch mit einem lokalen Backend-Server arbeiten, kann es vorkommen, dass die Netzwerkreaktionen zu schnell erfolgen, um die Netzwerkverzögerung zu erfassen, die ein tatsächlicher Benutzer erfahren würde, so dass Sie bei der Entwicklung eine künstliche Verzögerung hinzufügen können:
// ...
export const addTodo = ({ title, userId }) => {
return dispatch => {
dispatch(addTodoStarted());
axios
.post(ENDPOINT, {
title,
userId,
completed: false
})
.then(res => {
setTimeout(() => {
dispatch(addTodoSuccess(res.data));
}, 2500);
})
.catch(err => {
dispatch(addTodoFailure(err.message));
});
};
};
// ...
Um Fehlerszenarien auszuprobieren, können Sie einen Fehler manuell einwerfen:
// ...
export const addTodo = ({ title, userId }) => {
return dispatch => {
dispatch(addTodoStarted());
axios
.post(ENDPOINT, {
title,
userId,
completed: false
})
.then(res => {
throw new Error('addToDo error!');
// dispatch(addTodoSuccess(res.data));
})
.catch(err => {
dispatch(addTodoFailure(err.message));
});
};
};
// ...
Der Vollständigkeit halber hier ein Beispiel dafür, wie der Todo-Reducer aussehen könnte, um den gesamten Lebenszyklus der Anfrage zu bewältigen:
import {
ADD_TODO_SUCCESS,
ADD_TODO_FAILURE,
ADD_TODO_STARTED,
DELETE_TODO
} from '../actions/types';
const initialState = {
loading: false,
todos: [],
error: null
};
export default function todosReducer(state = initialState, action) {
switch (action.type) {
case ADD_TODO_STARTED:
return {
...state,
loading: true
};
case ADD_TODO_SUCCESS:
return {
...state,
loading: false,
error: null,
todos: [...state.todos, action.payload]
};
case ADD_TODO_FAILURE:
return {
...state,
loading: false,
error: action.payload.error
};
default:
return state;
}
}
getState
Neben dem Empfangen der Versandmethode aus dem Zustand empfängt die von einem asynchronen Aktionserzeuger mit Redux Thunk zurückgegebene Funktion auch die getState
Methode des Stores so, dass aktuelle Speicherwerte gelesen werden können:
export const addTodo = ({ title, userId }) => {
return (dispatch, getState) => {
dispatch(addTodoStarted());
console.log('current state:', getState());
// ...
};
};
Damit wird der aktuelle Zustand einfach auf die Konsole ausgedruckt.
Beispiel:
{loading: true, todos: Array(1), error: null}
Die Verwendung von getState
kann nützlich sein, die Dinge je nach aktuellen Zustand unterschiedlich zu handhaben. Wenn Sie beispielsweise die Anwendung auf nur vier ToDo-Einträge auf einmal beschränken möchten, können Sie von der Funktion zurückkehren, wenn der Status bereits die maximale Anzahl an ToDo-Einträgen enthält:
export const addTodo = ({ title, userId }) => {
return (dispatch, getState) => {
const { todos } = getState();
if (todos.length > 4) return;
dispatch(addTodoStarted());
// ...
};
};
Damit wird die Anwendung auf vier ToDo-Einträge beschränkt.
In diesem Tutorial haben Sie das Hinzufügen von Redux Thunk zu einer React-Anwendung untersucht, um das asynchrone Zuweisen von Aktionen zu ermöglichen. Dies ist nützlich, wenn ein Redux-Speicher verwendet wird und man sich auf externe APIs verlässt.
Wenn Sie mehr über React erfahren möchten, sehen Sie sich unsere Reihe Codieren in React.js an oder besuchen Sie unsere React-Themenseite für Übungen und Programmierprojekte.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Sign up for Infrastructure as a Newsletter.
Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.