Annuaire d'articles
Illustration
1. redux
npm installer redux --save
1.1 Présentation et principes d'utilisation
- C'est un outil dédié
状态管理的js库
(pas un plugin React) - Fonction : gérer de manière centralisée l'état partagé par plusieurs composants dans les applications React
- utiliser:
- L'état d'un certain composant doit être disponible à tout moment pour les autres composants.
(共享)
- Un composant doit changer l'état d'un autre composant
(通信)
- L'état d'un certain composant doit être disponible à tout moment pour les autres composants.
1.2 Flux de travail
Le diagramme de workflow redux est le suivant :
1.2.1 Trois noyaux
- action
- objet de l'action
- Contient deux attributs
type
: Identificateur d'attribut, la valeur est une chaîne, attribut unique et nécessairedata
: Attribut de données, valeur de tout type, attribut facultatif- exemple
{type:'CHANGE_NAME', data: {name: 'why'}}
- réducteur
- Utilisé pour l'initialisation et l'état de traitement
- Pendant le traitement, un nouvel état est généré sur la base de l'ancien état et de l'action.
纯函数
- exemple
if (type === 'CHANGE_NAME') {return { ...state, name }}
magasin
- Objets qui connectent ,
state
,action
reducer
- Pendant le traitement,
state和action
un nouvel état est généré sur la base de l'ancien.纯函数
1.3 magasin
- L'ensemble du fichier est divisé en modules
│ └─ store
│ ├─ actions // actions,文件夹内以模块区分
│ │ ├─ count.js
│ │ └─ person.js
│ ├─ constants.js // action type唯一标识常量
│ ├─ index.js // 入口文件
│ └─ reducer // reducer,文件夹内以模块区分
│ ├─ conut.js
│ ├─ index.js // reducer统一暴露文件,合并reducers
│ └─ persons.js
- Introduit
createStore
, spécifiquement utilisé pour créer l'objet de magasin le plus central dans Redux, etredux-thunk
applyMiddleware est utilisé pour prendre en charge les actions asynchrones.
npm je redux-pensez
// 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 action
- Définir
type类型
des valeurs constantes dans les objets d'action
// src/store/constants.js
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
- Créer une action, un retour d'action
对象
, un retour d'action asynchrone函数
peut être utilisé pour envoyer des requêtes réseau, une exécutionsetTimeout
, etc.
// 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
- L'action retardée ne veut pas être transmise au composant lui-même, mais à l'action
- Exécutez des méthodes asynchrones pour agir sur le statut, mais les données spécifiques doivent être renvoyées par la tâche asynchrone
1,5 réducteur
- La fonction réductrice recevra deux paramètres : l'état précédent
(state)
et l'objet d'action.(action)
- Obtenu à partir de l'objet d'action
type
,data
- Déterminer
type
comment traiter les données reducer
Lorsqu'il n'y a pas de valeur d'initialisation, c'estundefined
pour pouvoir définir la valeur initialeinitialState
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只读
- La seule façon de modifier l'État doit être le déclenchement
action
. N'essayez pas de modifier l'État d'une autre manière : cela garantit que toutes les modifications sont traitées et集中化处理
exécutées dans un ordre strict, il n'y a donc pas lieu de s'inquiéter des conditions de concurrence.
- La seule façon de modifier l'État doit être le déclenchement
-
Utiliser
纯函数
pour effectuer des modifications- Connectez l'ancien état et les actions via le réducteur et renvoyez un nouvel état :
- À mesure que la complexité de l’application augmente, nous pouvons
reducer拆分成多个小的reducers
opérer séparément ; - Mais tous les réducteurs devraient l'être
纯函数
, et ne peuvent en produire aucun副作用
;
1.5.1 Fusion des réducteurs
Grâce à combineReducers
la fusion, le paramètre reçu est un objet et la valeur clé de l'objet est cohérente avec la valeur clé de l'objet obtenue par getState().
// src/store/reducers/index.js
import {
combineReducers } from "redux";
import count from "./conut";
import persons from "./persons";
export default combineReducers({
count,
persons,
});
1.6 Envoi getState et mise à jour du statut
- Le composant récupère
getState()
les données du magasin dispatch
déclencher une action- Subscribe() termine la mise à jour de la vue
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. réagir-redux
2.1 Caractéristiques de base
- redux doit surveiller les modifications du magasin pour mettre à jour la vue et l'utiliser
store.subscribe(() => { this.forceUpdate(); })
; React-redux n'a pas besoin de surveiller - réagir-redux divise les composants en
UI组件
;容器组件
les opérations redux sont toutes dans des composants conteneurs. - Principe de responsabilité unique ; en
connect(mapStateToProps, mapDispatchToProps)(UI)
connectant les composants du conteneur et les composants de l'interface utilisateur ; redux n'a aucune distinction - Le composant d'interface utilisateur est responsable
UI的呈现
et le composant conteneur est responsable管理数据和逻辑
. Si un composant possède à la fois une logique d'interface utilisateur et une logique métier, divisez-le selon la structure suivante : un composant conteneur à l'extérieur et un composant d'interface utilisateur à l'intérieur. Le premier est chargé de communiquer avec l’extérieur, de transmettre les données au second, et le second restitue la vue.
2.2 connect()、mapStateToProps
React-Redux
Fournitconnect
des méthodes pourUI组件
générer à partir de容器组件
- Dans le code ci-dessous,
CountUI
ouiUI组件
,connect
le dernier exporté est容器组件
- Afin de définir la logique métier, les deux aspects d’informations suivants doivent être fournis :
Logique d'entrée : comment convertir des données externes (c'est-à-dire
state对象
) en paramètres des composants de l'interface utilisateur
Logique de sortie : comment convertir les actions émises par les utilisateurs en objets Action et les transmettre à partir des composants de l'interface utilisateur
connect
La méthode accepte deux paramètres : mapStateToProps
et mapDispatchToProps
. Ils définissent la logique métier du composant de l'interface utilisateur. Le premier est responsable de la logique d'entrée, qui est state
mappée aux paramètres du composant UI ( props
), et le second est responsable de la logique de sortie, c'est-à-dire que l'opération de l'utilisateur sur le composant UI est mappée pour Action
mapStateToProps
recevoir state
des paramètres, mapDispatchToProps
recevoir dispatch
des paramètres
// 容器组件
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
Est connect
le deuxième paramètre de la fonction, utilisé pour établir store.dispatch
le mappage des paramètres des composants de l'interface utilisateur aux méthodes. En d'autres termes, il définit quelles opérations utilisateur doivent être traitées comme Action
, et Store
il peut s'agir d'une fonction ou d'un objet qui lui est transmis.
- Si mapDispatchToProps est une fonction
/ 容器组件
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);
-
Si mapDispatchToProps est un objet
La valeur clé est une fonction,
Action creator
et la valeur renvoyée sera automatiquement émiseAction
parRedux
// mapDispatchToProps的简写,返回object
export default connect(mapStateToProps, {
increment: createIncrementAction,
incrementAsync: createIncrementAsyncAction,
decrement: createDecrementAction,
})(CountUI);
2.4Fournisseur
connect
Une fois que la méthode a généré le composant conteneur, celui-ci doit récupérer state
l'objet pour générer les paramètres du composant UI.
Une solution consiste à transmettre state
l'objet en tant que paramètre au composant conteneur. Cependant, cela est plus gênant, d'autant plus que le composant conteneur peut se trouver à un niveau très profond, et qu'il est très gênant de transmettre l'état niveau par niveau.
// 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 fournit
Provider
des composants qui permettent aux composants du conteneur d'obtenir un état Provider
Une couche est enroulée autour du composant racine, afin que tous les sous-composants de l'application puissent obtenir un état par défaut.
- Son principe est que les propriétés
React
du composantcontext
- Faites de l'application entière d'origine
Provider
un sous-composant pour la recevoir et transmettez-la au composant descendantRedux的store作为props
via l'objet.context
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, fonction combineReducers, redux-devtools
-
intergiciel
- Le but du middleware est d'étendre une partie de votre propre code entre ce qui
dispatch
est réaliséaction
et ce qui est finalement réalisé ;reducer
- Par exemple
日志记录
,调用异步接口
,添加代码调试功能
etc. ; redux-thunk
,applyMiddleware
utilisé pour prendre en charge les actions asynchrones,
- Le but du middleware est d'étendre une partie de votre propre code entre ce qui
-
combineReducers
fonction- Il fusionne également les réducteurs que nous avons transmis dans un objet et renvoie finalement une fonction de combinaison (équivalente à notre fonction de réduction précédente) ;
- Lors de l'exécution de la fonction de combinaison, il décidera s'il faut renvoyer l'état précédent ou le nouvel état en jugeant si les données renvoyées avant et après sont les mêmes ;
- Le nouvel état déclenchera le rafraîchissement correspondant de l'abonné, tandis que l'ancien état peut effectivement empêcher le rafraîchissement de l'abonné ;
-
redux-devtools
- Grâce à cet outil, nous pouvons savoir à chaque fois
状态是如何被修改的
,修改前后的状态变化
- Grâce à cet outil, nous pouvons savoir à chaque fois
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. Boîte à outils Redux
3.1 Fonctionnalités de base et API
- La boîte à outils Redux est également connue sous le nom de
RTK
npm install @reduxjs/toolkit réagir-redux
- Les API de base de Redux Toolkit sont principalement les suivantes :
configureStore
:WrappercreateStore
pour fournir des options de configuration simplifiées et de bonnes valeurs par défaut. Il compose automatiquement le vôtreslice reducer
, en ajoutant tout middleware Redux que vous fournissez, redux-thunk est inclus par défaut et en activant l'extension Redux DevTools.createSlice
: acceptereducer函数的对象
les noms de tranches et les valeurs d'état initiales, et génère automatiquement des réducteurs de tranches avec les actions correspondantes.createAsyncThunk
: prend une chaîne de type d'action et une fonction qui renvoie une promesse, et génère unpending/fulfilled/rejected
message qui distribue le type d'action en fonction de cette promesse
3.2 créerSlice
En createSlice
créant un slice
, createSlice contient principalement les paramètres suivants :
name
: Le nom marqué par l'utilisateur comme slice, le nom correspondant sera affiché plus tard dans redux-devtool ;initialState
: Valeur d'initialisation, la valeur à la première initialisation ;reducers
: Equivalent à la fonction réducteur précédente- Type d'objet, et de nombreuses fonctions peuvent être ajoutées ;
- La fonction est similaire à une instruction case dans le réducteur original de redux ;
- Paramètres de fonction :
state和action
appelez ceciaction时
,传递的action参数
;
extraReducers
Écoutez les résultats asynchrones
createSlice返回值是一个对象
, y compris toutes les actions ;
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 création de magasin
configureStore
Pour la créationstore对象
, les paramètres communs sont les suivants :reducer
, les réducteurs de la tranche peuvent être composés en un objet et transmis ici ;middleware
: Vous pouvez utiliser des paramètres pour transmettre d'autres middlewaresdevTools
: s'il faut configurer l'outil devTools, la valeur par défaut est 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 Fournir, connecter
- Fournir doit encore fournir un magasin
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 Opérations asynchrones de Redux Toolkit
Redux Toolkit a hérité par défaut des fonctions liées à Thunk :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
})
- Lorsque l'action créée par createAsyncThunk est distribuée, il y aura trois états :
pending
: L'action est lancée, mais il n'y a pas encore de résultat final ;fulfilled
: Obtenez le résultat final (résultat avec valeur de retour);rejected
: Il y a une erreur ou une exception est levée pendant l'exécution ;
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
appel en chaîne
// 异步操作(三种状态)(链式调用的形式)
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. crochets,useSelector、useDispatch
- createSlice crée un réducteur
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;
},
},
})
- Utiliser
useSelector
l'état d'accès/d'utilisation
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>
)
})
- En utilisant
useDispatch
le changement d'état,
useDispatch reçoit l'action dans les réducteurs que vous avez définis dans createSlice. Par exemple, passer l'incrément à useDispatch peut ajouter 1 à l'état.
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>
);
}
Article de référence : jjjona0215 maître