React-Redux (von flach nach tief)


Illustration
Fügen Sie hier eine Bildbeschreibung ein

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(通信)

1.2 Arbeitsablauf

Das Redux-Workflow-Diagramm sieht wie folgt aus:
Fügen Sie hier eine Bildbeschreibung ein

1.2.1 Drei Kerne

  • Aktion
    • Gegenstand der Handlung
    • Enthält zwei Attribute
      • type: Attributbezeichner, Wert ist eine Zeichenfolge, eindeutiges, notwendiges Attribut
      • data: 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,actionreducer
  • Bei der Verarbeitung state和actionwird 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, und redux-thunkapplyMiddleware 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ührung setTimeoutusw. 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
  • reducerWenn kein Initialisierungswert vorhanden ist, undefinedkö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;
  • 纯函数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拆分成多个小的reducersseparat arbeiten.
    • Aber alle Reduzierer sollten es sein 纯函数und können keine produzieren 副作用;

1.5.1 Reduzierstücke zusammenführen

Durch combineReducersdie 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
  • dispatchAktion 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.
    Fügen Sie hier eine Bildbeschreibung ein

2.2 connect()、mapStateToProps

  • React-ReduxStellt connectMethoden zum UI组件Generieren von bereit容器组件
  • Im folgenden Code ist CountUIja der zuletzt exportierte UI组件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

connectDie Methode akzeptiert zwei Parameter: mapStateToPropsund mapDispatchToProps. Sie definieren die Geschäftslogik der UI-Komponente. Ersteres ist für die Eingabelogik verantwortlich, die stateden 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
mapStateToPropsEmpfang statevon Parametern und mapDispatchToPropsdem Empfang dispatchvon 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

mapDispatchToPropsIst connectder zweite Parameter der Funktion, der zum Herstellen store.dispatchder 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 creatorund der zurückgegebene Wert wird automatisch Actionvon ausgegebenRedux

// mapDispatchToProps的简写,返回object
export default connect(mapStateToProps, {
    
    
  increment: createIncrementAction,
  incrementAsync: createIncrementAsyncAction,
  decrement: createDecrementAction,
})(CountUI);

2.4Anbieter

connectNachdem die Methode die Containerkomponente generiert hat, muss die Containerkomponente statedas Objekt abrufen, um die Parameter der UI-Komponente zu generieren. Eine Lösung besteht darin , das Objekt als Parameter an die Containerkomponente
zu übergeben . stateDies 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 ProviderKomponenten bereit, die es Containerkomponenten ermöglichen, ihren Status abzurufen
  • ProviderUm 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 Reactder Komponentecontext
  • Machen Sie die ursprüngliche gesamte Anwendung zu Providereiner Unterkomponente, um sie zu empfangen , und übergeben Sie sie Redux的store作为propsüber das Objekt contextan 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 dispatchErreichten actionund dem Endgültigen zu erweitern.reducer
    • Zum Beispiel 日志记录, 调用异步接口usw 添加代码调试功能.;
    • redux-thunk, applyMiddlewarewird zur Unterstützung asynchroner Aktionen verwendet,
  • combineReducersFunktion

    • 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 状态是如何被修改的,修改前后的状态变化
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 alsRTK

npm install @reduxjs/toolkit React-Redux

  • Die Kern-APIs von Redux Toolkit lauten hauptsächlich wie folgt:
    • configureStore:Wrapper createStore, um vereinfachte Konfigurationsoptionen und gute Standardeinstellungen bereitzustellen. Es erstellt automatisch Ihre eigene slice reducer, fügt die von Ihnen bereitgestellte Redux-Middleware hinzu, Redux-Thunk ist standardmäßig enthalten und aktiviert die Redux DevTools-Erweiterung.
    • createSlice: Akzeptiert reducer函数的对象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 einen pending/fulfilled/rejectedThunk, der den Aktionstyp basierend auf diesem Versprechen auslöst

3.2 createSlice

Durch createSlicedas Erstellen von one sliceenthä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和actionnennen Sie dies action时, 传递的action参数;
  • extraReducersAchten 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

  • configureStoreFür die Erstellung store对象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 übergeben
    • devTools: 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;
    },
  },
})
  • useSelectorZugriffs-/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 useDispatchden 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

Supongo que te gusta

Origin blog.csdn.net/weixin_46104934/article/details/131500441
Recomendado
Clasificación