Artikelverzeichnis
Illustration
1. redux
npm install redux --save
1.1 Übersicht und Nutzungsgrundsätze
- Es ist ein dediziertes Tool
状态管理的js库
(kein Reaktions-Plugin) - Funktion: Zentrale Verwaltung des von mehreren Komponenten gemeinsam genutzten Status in Reaktionsanwendungen
- verwenden:
- Der Status einer bestimmten Komponente muss jederzeit für andere Komponenten verfügbar sein.
(共享)
- Eine Komponente muss den Zustand einer anderen Komponente ändern
(通信)
- Der Status einer bestimmten Komponente muss jederzeit für andere Komponenten verfügbar sein.
1.2 Arbeitsablauf
Das Redux-Workflow-Diagramm sieht wie folgt aus:
1.2.1 Drei Kerne
- Aktion
- Gegenstand der Handlung
- Enthält zwei Attribute
type
: Attributbezeichner, Wert ist eine Zeichenfolge, eindeutiges, notwendiges Attributdata
: Datenattribut, Wert beliebiger Art, optionales Attribut- Beispiel
{type:'CHANGE_NAME', data: {name: 'why'}}
- Reduzierstück
- Wird für den Initialisierungs- und Verarbeitungsstatus verwendet
- Während der Verarbeitung wird basierend auf dem alten Status und der Aktion ein neuer Status generiert.
纯函数
- Beispiel
if (type === 'CHANGE_NAME') {return { ...state, name }}
speichern
- Objekte, die verbinden ,
state
,action
reducer
- Bei der Verarbeitung
state和action
wird auf Basis des alten ein neuer Zustand generiert .纯函数
1.3 Laden
- Die gesamte Datei ist in Module unterteilt
│ └─ store
│ ├─ actions // actions,文件夹内以模块区分
│ │ ├─ count.js
│ │ └─ person.js
│ ├─ constants.js // action type唯一标识常量
│ ├─ index.js // 入口文件
│ └─ reducer // reducer,文件夹内以模块区分
│ ├─ conut.js
│ ├─ index.js // reducer统一暴露文件,合并reducers
│ └─ persons.js
- Eingeführt
createStore
, speziell zum Erstellen des wichtigsten Speicherobjekts in Redux, undredux-thunk
applyMiddleware wird zur Unterstützung asynchroner Aktionen verwendet.
npm i redux-thunk
// src/store/index.js
import {
createStore, applyMiddleware } from "redux";
// 用于支持异步action
import thunk from "redux-thunk";
import reducers from "./reducers";
export default createStore(reducers, applyMiddleware(thunk));
1.4 Aktion
- Definieren Sie
type类型
konstante Werte in Aktionsobjekten
// src/store/constants.js
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
- Aktion erstellen, Aktion zurückgeben
对象
, asynchrone Aktion zurückgeben函数
kann zum Senden von Netzwerkanforderungen, zur AusführungsetTimeout
usw. verwendet werden.
// src/store/actions/count.js
import {
INCREMENT, DECREMENT } from "../constants";
// 普通action的值为object `{type: INCREMENT, data }`
export const increment = data => ({
type: INCREMENT, data });
export const decrement = data => ({
type: DECREMENT, data });
export const incrementAsync = (data) => {
return (dispatch) => {
setTimeout(() => {
dispatch(increment(data));
}, 500);
};
};
异步action
- Die verzögerte Aktion möchte nicht der Komponente selbst, sondern der Aktion zugeschrieben werden
- Führen Sie asynchrone Methoden aus, um den Status zu bearbeiten, die spezifischen Daten müssen jedoch von der asynchronen Aufgabe zurückgegeben werden
1,5 Reduzierer
- Die Reduzierfunktion erhält zwei Parameter: den vorherigen Zustand
(state)
und das Aktionsobjekt.(action)
- Vom Aktionsobjekt erhalten
type
,data
- Bestimmen Sie
type
, wie die Daten verarbeitet werden sollen reducer
Wenn kein Initialisierungswert vorhanden ist,undefined
können wir den Anfangswert festlegeninitialState
import {
INCREMENT, DECREMENT} from '../constants'
// 初始化状态
const initialState= 0;
export default function count(state = initialState, action) {
const {
type, data } = action;
switch (type) {
case INCREMENT:
return state + data;
case DECREMENT:
return state - data;
default:
return state;
}
}
注意
-
state只读
- Die einzige Möglichkeit, den Status zu ändern, muss das Auslösen sein
action
. Versuchen Sie nicht, den Status auf andere Weise zu ändern: Dadurch wird sichergestellt, dass alle Änderungen集中化处理
in strenger Reihenfolge verarbeitet und ausgeführt werden, sodass Sie sich keine Gedanken über Rennbedingungen machen müssen. Frage;
- Die einzige Möglichkeit, den Status zu ändern, muss das Auslösen sein
-
纯函数
Zum Durchführen von Änderungen verwenden- Verbinden Sie den alten Status und die Aktionen über den Reduzierer und geben Sie einen neuen Status zurück:
- Wenn die Komplexität der Anwendung zunimmt, können wir
reducer拆分成多个小的reducers
separat arbeiten. - Aber alle Reduzierer sollten es sein
纯函数
und können keine produzieren副作用
;
1.5.1 Reduzierstücke zusammenführen
Durch combineReducers
die Zusammenführung ist der empfangene Parameter ein Objekt, und der Schlüsselwert des Objekts stimmt mit dem durch getState () erhaltenen Schlüsselwert des Objekts überein.
// src/store/reducers/index.js
import {
combineReducers } from "redux";
import count from "./conut";
import persons from "./persons";
export default combineReducers({
count,
persons,
});
1.6 Versenden Sie getState und Statusaktualisierung
- Die Komponente
getState()
holt sich die Daten aus dem Store dispatch
Aktion auslösen- subscribe() schließt die Ansichtsaktualisierung ab
import store from "../../store";
import {
increment } from "../../store/action/count";
//redux内部不支持自动更新,需要通过subscribeAPI监听redux中状态变化,只有变化,就需要重新调用render
componentDidMount() {
store.subscribe(() => {
this.forceUpdate();
});
}
clickIncrement = () => {
store.dispatch(increment(+1));
};
render() {
return (
<div>
<h1>当前求和为: {
store.getState()}</h1>
...
<button onClick={
this.clickIncrement}>+</button>
</div>
)
}
2. React-Redux
2.1 Grundlegende Eigenschaften
- Redux muss Speicheränderungen überwachen, um die Ansicht zu aktualisieren und zu verwenden
store.subscribe(() => { this.forceUpdate(); })
; React-Redux muss nicht überwachen - React-Redux unterteilt Komponenten in
UI组件
;容器组件
Redux-Operationen befinden sich alle in Containerkomponenten. - Prinzip der Einzelverantwortung; durch
connect(mapStateToProps, mapDispatchToProps)(UI)
die Verbindung von Containerkomponenten und UI-Komponenten; bei Redux gibt es keinen Unterschied - Die UI-Komponente ist verantwortlich
UI的呈现
und die Containerkomponente ist verantwortlich管理数据和逻辑
. Wenn eine Komponente sowohl über eine Benutzeroberfläche als auch über eine Geschäftslogik verfügt, teilen Sie sie in die folgende Struktur auf: eine Containerkomponente außen und eine UI-Komponente innen. Ersterer ist für die Kommunikation mit der Außenwelt verantwortlich, leitet Daten an Letzteren weiter und Letzterer rendert die Ansicht.
2.2 connect()、mapStateToProps
React-Redux
Stelltconnect
Methoden zumUI组件
Generieren von bereit容器组件
- Im folgenden Code ist
CountUI
ja der zuletzt exportierteUI组件
Codeconnect
容器组件
- Um die Geschäftslogik zu definieren, müssen die folgenden zwei Informationsaspekte angegeben werden:
Eingabelogik: So konvertieren Sie externe Daten (z. B.
state对象
) in Parameter von UI-Komponenten.
Ausgabelogik: So konvertieren Sie von Benutzern ausgegebene Aktionen in Aktionsobjekte und geben sie von UI-Komponenten weiter
connect
Die Methode akzeptiert zwei Parameter: mapStateToProps
und mapDispatchToProps
. Sie definieren die Geschäftslogik der UI-Komponente. Ersteres ist für die Eingabelogik verantwortlich, die state
den Parametern der UI-Komponente ( props
) zugeordnet ist, und letzteres ist für die Ausgabelogik verantwortlich, dh die Operationen des Benutzers an der UI-Komponente werden dem Action
mapStateToProps
Empfang state
von Parametern und mapDispatchToProps
dem Empfang dispatch
von Parametern zugeordnet
// 容器组件
import {
connect } from "react-redux";
import CountUI from "../../components/count";
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction,
} from "../../redux/count_action";
const mapStateToProps = (state) => ({
count: state });
const mapDispatchToProps = (dispatch) => ({
increment: (number) => {
dispatch(createIncrementAction(number));
},
incrementAsync: (number) => {
dispatch(createIncrementAsyncAction(number, 500));
},
decrement: (number) => {
dispatch(createDecrementAction(number));
},
});
export default connect(mapStateToProps, mapDispatchToProps)(CountUI);
// UI组件
import React, {
Component } from "react";
export default class CountUI extends Component {
// 加法
increment = () => {
const {
value } = this.selectNumber;
this.props.increment(value * 1);
};
// 减法
decrement = () => {
const {
value } = this.selectNumber;
this.props.decrement(value * 1);
};
// 奇数加
incrementIfOdd = () => {
if (this.props.count % 2 === 1) {
const {
value } = this.selectNumber;
this.props.increment(value * 1);
}
};
// 异步加
incrementAsync = () => {
const {
value } = this.selectNumber;
this.props.increment(value * 1);
};
render() {
return (
<div>
<h1>当前求和为: {
this.props.count}</h1>
...
</div>
);
}
}
2.3 mapDispatchToProps
mapDispatchToProps
Ist connect
der zweite Parameter der Funktion, der zum Herstellen store.dispatch
der Zuordnung von UI-Komponentenparametern zu Methoden verwendet wird. Mit anderen Worten, es definiert, welche Benutzeroperationen als behandelt werden sollen Action
, und Store
es kann sich um eine Funktion oder ein Objekt handeln, das an ihn übergeben wird.
- Wenn „mapDispatchToProps“ eine Funktion ist
/ 容器组件
const mapDispatchToProps = (dispatch) => ({
increment: (number) => {
dispatch(createIncrementAction(number));
},
incrementAsync: (number) => {
dispatch(createIncrementAsyncAction(number));
},
decrement: (number) => {
dispatch(createDecrementAction(number));
},
});
// mapDispatchToProps的一般写法,返回function
export default connect(mapStateToProps, mapDispatchToProps)(CountUI);
-
Wenn „mapDispatchToProps“ ein Objekt ist
Der Schlüsselwert ist eine Funktion,
Action creator
und der zurückgegebene Wert wird automatischAction
von ausgegebenRedux
// mapDispatchToProps的简写,返回object
export default connect(mapStateToProps, {
increment: createIncrementAction,
incrementAsync: createIncrementAsyncAction,
decrement: createDecrementAction,
})(CountUI);
2.4Anbieter
connect
Nachdem die Methode die Containerkomponente generiert hat, muss die Containerkomponente state
das Objekt abrufen, um die Parameter der UI-Komponente zu generieren. Eine Lösung besteht darin , das Objekt als Parameter an die Containerkomponente
zu übergeben . state
Dies ist jedoch problematischer, insbesondere da sich die Containerkomponente möglicherweise auf einer sehr tiefen Ebene befindet und es sehr mühsam ist, den Status Ebene für Ebene weiterzugeben.
// src/App.js
import React, {
Component } from "react";
import Count from "./container/count";
import store from "./redux/store";
export default class App extends Component {
render() {
return <Count store={
store} />;
}
}
- React-Redux stellt
Provider
Komponenten bereit, die es Containerkomponenten ermöglichen, ihren Status abzurufen Provider
Um die Stammkomponente wird eine Ebene gewickelt, sodass alle Unterkomponenten der App standardmäßig den Status erhalten können.
- Sein Prinzip besteht darin, dass die Eigenschaften
React
der Komponentecontext
- Machen Sie die ursprüngliche gesamte Anwendung zu
Provider
einer Unterkomponente, um sie zu empfangen , und übergeben Sie sieRedux的store作为props
über das Objektcontext
an die untergeordnete Komponente .connect
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {
Provider } from "react-redux"
import store from "./store"
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
// <React.StrictMode>
<Provider store={
store}>
<App />
</Provider>
// </React.StrictMode>
);
2.5. Middleware, CombineReducers-Funktion, Redux-Devtools
-
Middleware
- Der Zweck der Middleware besteht darin, einen Teil Ihres eigenen Codes zwischen dem
dispatch
Erreichtenaction
und dem Endgültigen zu erweitern.reducer
- Zum Beispiel
日志记录
,调用异步接口
usw添加代码调试功能
.; redux-thunk
,applyMiddleware
wird zur Unterstützung asynchroner Aktionen verwendet,
- Der Zweck der Middleware besteht darin, einen Teil Ihres eigenen Codes zwischen dem
-
combineReducers
Funktion- Außerdem werden die von uns übergebenen Reduzierer in einem Objekt zusammengeführt und schließlich eine Kombinationsfunktion zurückgegeben (entspricht unserer vorherigen Reduziererfunktion).
- Während der Ausführung der Kombinationsfunktion wird entschieden, ob der vorherige Status oder der neue Status zurückgegeben werden soll, indem beurteilt wird, ob die vorher und nachher zurückgegebenen Daten gleich sind.
- Der neue Status löst die entsprechende Aktualisierung des Abonnenten aus, während der alte Status die Aktualisierung des Abonnenten effektiv verhindern kann.
-
redux-devtools
- Mit diesem Tool können wir jederzeit wissen
状态是如何被修改的
,修改前后的状态变化
- Mit diesem Tool können wir jederzeit wissen
import {
applyMiddleware, compose, createStore,combineReducers } from 'redux';
import thunk from 'redux-thunk';
import count from "./conut";
import persons from "./persons";
const reducer= combineReducers({
count,
persons,
});
//创建store 传递reducer
// redux-devtools
// trace 开启
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
trace: true }) || compose;
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))
3. Redux-Toolkit
3. 1 Grundfunktionen und API
- Redux Toolkit ist auch bekannt als
RTK
npm install @reduxjs/toolkit React-Redux
- Die Kern-APIs von Redux Toolkit lauten hauptsächlich wie folgt:
configureStore
:WrappercreateStore
, um vereinfachte Konfigurationsoptionen und gute Standardeinstellungen bereitzustellen. Es erstellt automatisch Ihre eigeneslice reducer
, fügt die von Ihnen bereitgestellte Redux-Middleware hinzu, Redux-Thunk ist standardmäßig enthalten und aktiviert die Redux DevTools-Erweiterung.createSlice
: Akzeptiertreducer函数的对象
Slice-Namen und Anfangszustandswerte und generiert automatisch Slice-Reduzierer mit entsprechenden Aktionen.createAsyncThunk
: Nimmt eine Aktionstypzeichenfolge und eine Funktion, die ein Versprechen zurückgibt, und generiert einenpending/fulfilled/rejected
Thunk, der den Aktionstyp basierend auf diesem Versprechen auslöst
3.2 createSlice
Durch createSlice
das Erstellen von one slice
enthält createSlice hauptsächlich die folgenden Parameter:
name
: Das vom Benutzer als Slice markierte Substantiv. Das entsprechende Substantiv wird später in redux-devtool angezeigt.initialState
: Initialisierungswert, der Wert bei der ersten Initialisierung;reducers
: Entspricht der vorherigen Reduzierfunktion- Objekttyp und viele Funktionen können hinzugefügt werden;
- Die Funktion ähnelt einer case-Anweisung im ursprünglichen Redux-Reduzierer;
- Funktionsparameter:
state和action
nennen Sie diesaction时
,传递的action参数
;
extraReducers
Achten Sie auf asynchrone Ergebnisse
createSlice返回值是一个对象
, einschließlich aller Aktionen;
import {
createSlice } from '@reduxjs/toolkit';
const homeReducer = createSlice({
name: 'home',
initialState: {
banners: [],
recommends: []
},
reducers: {
changeRecommendActios(state, {
paylaod }) {
state.recommends=paylaod
},
changeBannerActions(state, {
payload }) {
state.banners=payload
}
}
})
export const {
changeBannerActions, changeRecommendActios } = homeReducer.actions
export default homeReducer.reducer
3.3 Shop-Erstellung
configureStore
Für die Erstellungstore对象
gelten folgende allgemeine Parameter:reducer
, die Reduzierer im Slice können zu einem Objekt zusammengesetzt und hier übergeben werden;middleware
: Sie können Parameter verwenden, um andere Middleware zu übergebendevTools
: Ob das devTools-Tool konfiguriert werden soll, der Standardwert ist true;
import {
configureStore } from '@reduxjs/toolkit';
import counterReducer from './modules/Counter';
import homeReducer from './modules/Home';
const store = configureStore({
reducer: {
// 这里做分包
counter: counterReducer,
home: homeReducer
}
})
export default store
3.4 Bereitstellen und Verbinden
- Provide muss noch einen Laden bereitstellen
import React from "react";
import ReactDOM from "react-dom/client";
import {
Provider } from 'react-redux';
import App from "./App";
import store from './store';
const root = ReactDOM.createRoot(document.getElementById("root"));
// 1. react-redux使用 第一步提供全局store
root.render(
// 严格模式 render执行两次
<Provider store={
store} >
<App />
</Provider>
);
3.5 Asynchrone Operationen des Redux Toolkits
Redux Toolkit hat standardmäßig Thunk-bezogene Funktionen für uns geerbt:createAsyncThunk
import {
createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import axios from 'axios';
export const fetachHomeActions = createAsyncThunk('home/multidata', async (payload, extraInfo) => {
const res = await axios.get("http://123.207.32.32:8000/home/multidata")
return res.data
})
- Wenn die von createAsyncThunk erstellte Aktion ausgelöst wird, gibt es drei Zustände:
pending
: Die Klage wird ausgegeben, aber es gibt noch kein endgültiges Ergebnis;fulfilled
: Holen Sie sich das Endergebnis (Ergebnis mit Rückgabewert);rejected
: Während der Ausführung ist ein Fehler aufgetreten oder es wird eine Ausnahme ausgelöst.
import {
createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import axios from 'axios';
export const fetachHomeActions = createAsyncThunk('home/multidata', async (payload, extraInfo) => {
const res = await axios.get("http://123.207.32.32:8000/home/multidata")
return res.data
})
const homeReducer = createSlice({
name: 'home',
initialState: {
banners: [],
recommends: []
},
reducers: {
changeRecommendActios(state, {
paylaod }) {
state.recommends = paylaod
},
changeBannerActions(
state, {
payload }
) {
state.banners = payload
}
},
// 异步操作(三种状态)
extraReducers: {
[fetachHomeActions.pending](state, action) {
console.log(action);
},
[fetachHomeActions.fulfilled](state, {
payload }) {
state.banners=payload.data.banner.list
},
[fetachHomeActions.rejected](sate, action) {
}
}
})
export const {
changeBannerActions, changeRecommendActios } = homeReducer.actions
export default homeReducer.reducer
Kettenruf
// 异步操作(三种状态)(链式调用的形式)
extraReducers: (builder) => {
builder.addCase(fetachHomeActions.pending, (state, action) => {
console.log("fetachHomeActions pending")
}).addCase(fetachHomeActions.fulfilled, (state, {
payload }) => {
state.banners = payload.data.banner.list
state.recommends = payload.data.recommend.list
})
}
4. Haken, useSelector, useDispatch
- createSlice erstellt einen Reduzierer
import {
createSlice } from '@reduxjs/toolkit';
const initialState = {
value: 0,
};
export const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
},
})
useSelector
Zugriffs-/Nutzungsstatus verwenden
const {
counter} = useSelector((state) => state.counter.counter);
// 优化
// 1. memo包裹只有只有props改变才会重新渲染
// 2.第二个参数shallowEqual 进行浅层比较 (就是reducer中返回完全相同的对象 才不进行重新渲染)
// shallowEqual 解决使用相同的参数调用时,useSelector返回不同的结果。这可能导致不必要的重新渲染。
const App = memo((props) => {
const {
counter } = useSelector((state) => ({
counte: state.counter.counter
}),shallowEqual)
return (
<div>
<h1>{
counter}</h1>
</div>
)
})
- Wenn Sie
useDispatch
den Status ändern,
empfängt useDispatch die Aktion in den Reduzierern, die Sie in createSlice definiert haben. Durch die Übergabe von Inkrement an useDispatch kann beispielsweise 1 zum Status hinzugefügt werden.
import {
useSelector, useDispatch } from 'react-redux';
import {
decrement,
increment,
} from './counterSlice';
export function Counter() {
const count = useSelector((state) => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<div>
<button
aria-label="Decrement value"
onClick={
() => dispatch(decrement())}
>
-
</button>
<span>{
count}</span>
<button
aria-label="Increment value"
onClick={
() => dispatch(increment())}
>
+
</button>
</div>
</div>
);
}
Referenzartikel: jjjona0215 Master