亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

淺談redux以及react-redux簡(jiǎn)單實(shí)現(xiàn)

 更新時(shí)間:2018年08月28日 10:27:04   作者:emsoft  
這篇文章主要介紹了淺談redux以及react-redux簡(jiǎn)單實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

寫在前頭

redux 簡(jiǎn)介

隨著 JavaScript 單頁應(yīng)用開發(fā)日趨復(fù)雜,JavaScript 需要管理比任何時(shí)候都要多的 state (狀態(tài))。 這些 state 可能包括服務(wù)器響應(yīng)、緩存數(shù)據(jù)、本地生成尚未持久化到服務(wù)器的數(shù)據(jù),也包括 UI 狀態(tài),如激活的路由,被選中的標(biāo)簽,是否顯示加載動(dòng)效或者分頁器等等。

管理不斷變化的 state 非常困難。如果一個(gè) model 的變化會(huì)引起另一個(gè) model 變化,那么當(dāng) view 變化時(shí),就可能引起對(duì)應(yīng) model 以及另一個(gè) model 的變化,依次地,可能會(huì)引起另一個(gè) view 的變化。直至你搞不清楚到底發(fā)生了什么。state 在什么時(shí)候,由于什么原因,如何變化已然不受控制。 當(dāng)系統(tǒng)變得錯(cuò)綜復(fù)雜的時(shí)候,想重現(xiàn)問題或者添加新功能就會(huì)變得舉步維艱。

如果這還不夠糟糕,考慮一些來自前端開發(fā)領(lǐng)域的新需求,如更新調(diào)優(yōu)、服務(wù)端渲染、路由跳轉(zhuǎn)前請(qǐng)求數(shù)據(jù)等等。前端開發(fā)者正在經(jīng)受前所未有的復(fù)雜性,難道就這么放棄了嗎?當(dāng)然不是。

這里的復(fù)雜性很大程度上來自于:我們總是將兩個(gè)難以理清的概念混淆在一起:變化和異步。 如果把二者分開,能做的很好,但混到一起,就變得一團(tuán)糟。一些庫如 React 試圖在視圖層禁止異步和直接操作 DOM 來解決這個(gè)問題。美中不足的是,React 依舊把處理 state 中數(shù)據(jù)的問題留給了我們自己。而 redux 就可以來幫我管理這些狀態(tài);

demo 演示

demo 結(jié)構(gòu)樹
├── config-overrides.js
├── .gitignore
├── package.json
├── package-lock.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
├── README.md
└── src
 ├── App.js
 ├── Demo
 │ ├── actionCreate.js
 │ ├── Demo.jsx
 │ ├── react-redux.js
 │ ├── reducer.js
 │ ├── redux.js
 │ ├── style.css
 │ └── thunk.js
 └── index.js

一、 redux API createStore 的實(shí)現(xiàn)

  首先我們先結(jié)合 reducer 以及 action 的知識(shí)簡(jiǎn)單實(shí)現(xiàn)開頭展示的 demo, 并逐步揭曉 createStore 的神秘面紗;

1.1 準(zhǔn)備工作:

創(chuàng)建 reducer 并導(dǎo)出 reducer
// reducer.js
const initState = { user: 'qianyin', age: 18, sex: '男' };
export const reducer = (state=initState, action) => {
 switch(action.type){
 case 'USER_UPDATE':
  return {...state, ...action.payload};
 case 'AGE_GROW':
  return {...state, age: state.age + 1};
 case 'SEX_UPDATE':
  return {...state, ...action.payload};
 default:
  return state;
 }
}
創(chuàng)建 action 創(chuàng)建函數(shù)
// actionCreate.js
export const changeUser = (user) => {
 return {
 payload:{user},
 type: 'USER_UPDATE',
 };
}

export const changeAge = () => {
 return { type: 'AGE_GROW' };
}
通過 react 在頁面上預(yù)先繪制出基本的元素
/* style.css */
.btn{
 height: 31px;

}
.input{
 height: 25px;
}
// Demo.jsx
import React from 'react';
import './style.css';

export default class Demo extends React.Component{
 onChange = () => {}
 onClick = () => {}
 render(){
 return (
  <div>
  <p>user: xxx, age: xxx</p>
  user: 
  <input type="text" className="input" onChange={this.onChange}/>
  &nbsp;
  <button className="btn" onClick={this.onClick}>年齡增長</button>
  </div>
 );
 }
}
最終頁面將渲染如下:

1.2 demo 的初次實(shí)現(xiàn)代碼

  • 創(chuàng)建全局狀態(tài) state;
  • 創(chuàng)建監(jiān)聽隊(duì)列;
  • 針對(duì)監(jiān)聽隊(duì)列,新增函數(shù)用于將指定監(jiān)聽對(duì)象添加到隊(duì)列中;
  • 在函數(shù) dispatch 中執(zhí)行 reducer 將返回值作為新的 state, 同時(shí)依次執(zhí)行監(jiān)聽對(duì)象;
  • 默認(rèn)執(zhí)行一次 dispatch 給定一個(gè) type 相對(duì)唯一的 action, 目的是為了匹配 reducer 的默認(rèn)狀態(tài)值,從而實(shí)現(xiàn)對(duì) redux state 的初始化;
  • 在組件 Demo 通過在函數(shù) update 使用 this.setState 將全局 state 保存到 react state 中,并將函數(shù) update 添加到監(jiān)聽隊(duì)列中;從而使得當(dāng)我們一旦試圖通過 dispatch 修改全局狀態(tài)時(shí),能夠及時(shí)更新 react state 最終觸發(fā) react 生命周期 render;
  • 在 react 生命周期 componentDidMount 中我們除了將 update 添加到監(jiān)聽隊(duì)列以外,還需手動(dòng)執(zhí)行一次 update 其主要目的就是為了首次初始化 react state;
// Demo.jsx
import React from 'react';
import { changeAge, changeUser } from './actionCreate';
import { reducer } from './reducer';
import './style.css';

let state;
const listeners = [];
const subscribe = (listener) => {
 listeners.push(listener);
}
const dispatch = (action) => {
 state = reducer(state, action);
 console.log(state);
 listeners.forEach(v => v());
}
dispatch({type: '%$&HJKAJJHDJHJ'});

export default class Demo extends React.Component{
 state = {user: 'xxx', age: 'xxx'};
 componentDidMount(){
 subscribe(this.update);
 this.update();
 }

 update = () => {
 this.setState(state);
 }

 onChange = (e) => {
 dispatch(changeUser(e.target.value));
 }

 onClick = () => {
 dispatch(changeAge());
 }

 render(){
 return (
  <div>
  <p>user: {this.state.user}, age: {this.state.age}</p>
  user: 
  <input type="text" className="input" onChange={this.onChange}/>
  &nbsp;
  <button className="btn" onClick={this.onClick}>年齡增長</button>
  </div>
 );
 }
}

1.3 API createStore 的實(shí)現(xiàn)

其實(shí)上文的代碼中對(duì)于 createStore 的實(shí)現(xiàn)原理已經(jīng)基本描述清除,下面我們只是單純的對(duì)代碼進(jìn)行了簡(jiǎn)單的封裝;當(dāng)然為了能夠獲取到 state 我們專門增加了一個(gè)函數(shù) getState 來實(shí)現(xiàn)它;

createStore 函數(shù)實(shí)現(xiàn)
// redux.js

export const createStore = (reducer) => {
 // 聲明常量
 let state;
 const listeners = [];

 // 獲取狀態(tài)
 const getState = () => {
 return state;
 }

 // 添加監(jiān)聽對(duì)象
 const subscribe = (listener) => {
 listeners.push(listener);
 }

 // [1]執(zhí)行reducer修改狀態(tài) [2]遍歷執(zhí)行監(jiān)聽對(duì)象
 const dispatch = (action) => {
 state = reducer(state, action);
 listeners.forEach(v => v());
 }

 // 初始化 state
 dispatch({type: '%$&HJKAJJHDJHJ'});
 
 // 暴露接口
 return {getState, subscribe, dispatch};
}
調(diào)用 createStore 并對(duì) demo 進(jìn)行修改
// Demo.jsx
import React from 'react';
import './style.css';
import { changeAge, changeUser } from './actionCreate';
import { reducer } from './reducer';
import { createStore } from './redux';

const store = createStore(reducer);

export default class Demo extends React.Component{
 state = {user: 'xxx', age: 'xxx'};
 componentDidMount(){
 store.subscribe(this.update);
 this.update();
 }

 update = () => {
 this.setState(store.getState());
 }

 onChange = (e) => {
 store.dispatch(changeUser(e.target.value));
 }

 onClick = () => {
 store.dispatch(changeAge());
 }

 render(){
 return (
  <div>
  <p>user: {this.state.user}, age: {this.state.age}</p>
  user: 
  <input type="text" className="input" onChange={this.onChange}/>
  &nbsp;
  <button className="btn" onClick={this.onClick}>年齡增長</button>
  </div>
 );
 }
}

二、 react-redux API Provider 的實(shí)現(xiàn)

在 react 中大多數(shù)情況下我們需要將狀態(tài)傳遞給后代組件進(jìn)行使用的,當(dāng)然通過 props 是可以實(shí)現(xiàn)狀態(tài)從父級(jí)到子級(jí)的傳遞,但是當(dāng)狀態(tài)需要傳遞的層級(jí)比較深的情況下再使用 props 就顯得無力了,那么在 react-redux 中它是如何實(shí)現(xiàn)對(duì) store 的傳遞的呢?

2.1 react context 的引入

在 App.js 中創(chuàng)建 store 并通過 context 傳遞 store
// App.js
import React, { Component } from 'react';
import propTypes from 'prop-types';
import { createStore } from './Demo/redux';
import { reducer } from './Demo/reducer';
import Demo from './Demo/Demo';

// 創(chuàng)建 store
const store = createStore(reducer);

class App extends Component {
 // 聲明 childContextTypes 狀態(tài)屬性類型
 static childContextTypes = {
 store: propTypes.object
 };
 // 設(shè)置 childContext
 getChildContext(){
 return {store}
 }
 render() {
 return <Demo />;
 }
}
export default App;
在子組件 Demo 中通過 context 獲取 store 并對(duì)代碼進(jìn)行簡(jiǎn)單修改
// Demo.jsx
import React from 'react';
import propTypes from 'prop-types';
import './style.css';
import { changeAge, changeUser } from './actionCreate';

export default class Demo extends React.Component{
 // 設(shè)置 context 狀態(tài)值類型
 static contextTypes = {
 store: propTypes.object
 };

 constructor(props, context){
 super(props, context);
 // 獲取store
 this.store = context.store;
 this.state = {user: 'xxx', age: 'xxx'};
 }
 
 componentDidMount(){
 this.store.subscribe(this.update);
 this.update();
 }

 update = () => {
 this.setState(this.store.getState());
 }

 onChange = (e) => {
 this.store.dispatch(changeUser(e.target.value));
 }

 onClick = () => {
 this.store.dispatch(changeAge());
 }

 render(){
 return (
  <div>
  <p>user: {this.state.user}, age: {this.state.age}</p>
  user: 
  <input type="text" className="input" onChange={this.onChange}/>
  &nbsp;
  <button className="btn" onClick={this.onClick}>年齡增長</button>
  </div>
 );
 }
}

2.2 封裝代碼實(shí)現(xiàn) Provider

通過 react context 我們實(shí)現(xiàn)了對(duì) store 的傳遞,到這里 Provider 的功能以及實(shí)現(xiàn)原理基本上應(yīng)該算是清晰了,無非就是對(duì)組件進(jìn)行包裹同時(shí)通過 react context 來傳遞共享 store;那么接下來我們通過對(duì)代碼的封裝來實(shí)現(xiàn) Provider 組件;

Provider 組件:實(shí)現(xiàn)對(duì) store 的傳遞
// react-redux.js
import React from 'react';
import propTypes from 'prop-types';

export class Provider extends React.Component{
 // 設(shè)置 childContext 狀態(tài)值類型
 static childContextTypes = {
 store: propTypes.object
 };

 // 設(shè)置 childContext
 getChildContext(){
 return {store: this.props.store}
 }
 
 render(){
 return this.props.children;
 }
}
重寫 App.js: 對(duì) Provider 組件的調(diào)用
// App.js
import React, { Component } from 'react';
import { createStore } from './Demo/redux';
import { Provider } from './Demo/react-redux';
import { reducer } from './Demo/reducer';
import Demo from './Demo/Demo';

// 創(chuàng)建 store
const store = createStore(reducer);

class App extends Component {
 render() {
 // 調(diào)用接口 Provider
 return <Provider store={store}><Demo /></Provider>;
 }
}
export default App;

三、 react-redux API connect 高階組件的實(shí)現(xiàn)

上文中在后代組件如果需要獲取 store 則需要手動(dòng)通過獲取 react context 來調(diào)用 store 并且需要顯性的調(diào)用 store 內(nèi)部的方法來進(jìn)行一些操作;接下來我們來實(shí)現(xiàn)這么一個(gè)高階組件 connect,我們只需要提供所需的 redux state 以及 action 創(chuàng)建函數(shù),即可通過 props 獲取到相應(yīng)的 redux state , 并且允許直接通過 props 調(diào)用action 創(chuàng)建函數(shù)來試圖修改 redux state ;

創(chuàng)建高階組件 connect
// react-redux.js
export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
 return class NewComponent extends React.Component{
 render(){
  return <Component />
 }
 }
}
獲取store
// react-redux.js
export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
 return class NewComponent extends React.Component{
 // 設(shè)置 context 狀態(tài)值類型
 static contextType = {
  store: propTypes.object
 };
  // [1]獲取 store [2]設(shè)置空 react state
 constructor(props, context){
  super(props, context);
  this.store = context.store;
  this.state = {};
 }
 render(){
  return <Component />
 }
 }
}
添加監(jiān)聽對(duì)象,并嘗試通過 props 將狀態(tài)傳遞給子組件
export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
 return class NewComponent extends React.Component{
 static contextType = {
  store: propTypes.object
 };
 constructor(props, context){
  super(props, context);
  this.store = context.store;
  this.state = {};
 }
  // [1]添加監(jiān)聽對(duì)象 [2]手動(dòng)執(zhí)行監(jiān)聽對(duì)象,初始化 react state
 componentDidMount(){
  this.store.subscribe(this.update);
  this.update();
 }
 
 update = () => {
  // 獲取全部redux state 并添加到 react state
  const state = this.store.getState();
  this.setState(state);
 }
 render(){
  // 通過 props 將 react state 全部傳給子組件
  return <Component {...this.state} />
 }
 }
}
通過 mapStateToProps 獲取指定 redux state
// react-redux.js
export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
 return class NewComponent extends React.Component{
 static contextType = {
  store: propTypes.object
 };
 constructor(props, context){
  super(props, context);
  this.store = context.store;
  this.state = {};
 }
 componentDidMount(){
  this.store.subscribe(this.update);
  this.update();
 }
 
 update = () => {
  // 執(zhí)行 mapStateToProps 只獲取用戶指定需求的 state
  const state = this.store.getState();
  const filterState = mapStateToProps(state);
  this.setState(filterState);
 }
 render(){
  return <Component {...this.state} />
 }
 }
}
通過 mapDispatchToProps 獲取 action 創(chuàng)建函數(shù): 使用 dispatch 包裹后返回
// react-redux.js
// react-redux.js
export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
 return class NewComponent extends React.Component{
 static contextTypes = {
  store: propTypes.object
 };
 constructor(props, context){
  super(props, context);
  this.store = context.store;
  this.state = {};
 }
 componentDidMount(){
  this.store.subscribe(this.update);
  this.update();
 }
 
 update = () => {
  // 處理 state ===> 獲取用戶指定的 state
  const state = this.store.getState();
  const filterState = mapStateToProps(state);

  // 使用 dispatch 對(duì) mapDispatchToProps 中的 action 創(chuàng)建函數(shù)進(jìn)行包裹后返回
  const actionFun = {};
  for(let key in mapDispatchToProps){
  actionFun[key] = (...args) => {
   this.store.dispatch(mapDispatchToProps[key](...args));
  }
  }
 // 一種簡(jiǎn)寫方式: 騷操作
 // const actionFun = Object.keys(mapDispatchToProps)
 // .reduce((total, item) => {
 // return { ...total, [item]: (...args) => {dispatch(mapDispatchToProps[item](...args));}
 // } } ,{});

  this.setState({...filterState, ...actionFun});
 }
 render(){
  return <Component {...this.state} />
 }
 }
}
調(diào)用高階組件:修改 Demo.jsx
// Demo.jsx
import React from 'react';
import { changeAge, changeUser } from './actionCreate';
import { connect } from './react-redux';
import './style.css';

// 編寫 mapStateToProps 參數(shù) redux state 返回所需的 redux state
const mapStateToProps = (state) => {
 return {user: state.user, age: state.age};
}

// 調(diào)用高階組件
@connect(mapStateToProps, {changeAge, changeUser})
export default class Demo extends React.Component{
 onChange = (e) => {
 this.props.changeUser(e.target.value);
 }
 onClick = () => {
 this.props.changeAge();
 }
 render(){
 return (
  <div>
  <p>user: {this.props.user}, age: {this.props.age}</p>
  user: 
  <input type="text" className="input" onChange={this.onChange}/>
  &nbsp;
  <button className="btn" onClick={this.onClick}>年齡增長</button>
  </div>
 );
 }
}

四、redux API bindactioncreators 的實(shí)現(xiàn)

在上文我們對(duì) mapDispatchToProps 的處理過程就是 API bindactioncreators 的功能: 將給定 action 創(chuàng)建函數(shù)使用 dispatch 進(jìn)行包裹后返回;

封裝 bindactioncreators
// redux.js
export const bindactioncreators = (mapDispatchToProps, dispatch) => {
 const actionFun = {};
 // 遍歷 mapDispatchToProps 中每個(gè) action 創(chuàng)建函數(shù) 并使用 dispatch 包裹后返回
 for(let key in mapDispatchToProps){
 actionFun[key] = (...args) => {
  dispatch(mapDispatchToProps[key](...args));
 }
 }

 return actionFun;
 // 一種簡(jiǎn)寫方式: 騷操作
 // return actionFun = Object.keys(mapDispatchToProps)
 // .reduce((total, item) => {
 // return { ...total, [item]: (...args) => {dispatch(mapDispatchToProps[item](...args));}
 // } } ,{});
}
修改 connect :
// react-redux.js
import { bindactioncreators } from './redux';
....
export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
 return class NewComponent extends React.Component{
 static contextTypes = {
  store: propTypes.object
 };
 constructor(props, context){
  super(props, context);
  this.store = context.store;
  this.state = {};
 }
 componentDidMount(){
  this.store.subscribe(this.update);
  this.update();
 }
 
 update = () => {
  const state = this.store.getState();
  const filterState = mapStateToProps(state);
  
  // 調(diào)用 API bindactioncreators 
  // 對(duì) mapDispatchToProps 內(nèi)每個(gè) action 創(chuàng)建函數(shù)使用 dispatch 進(jìn)行包裹后返回
  const actionFun = bindactioncreators(mapDispatchToProps, this.store.dispatch);
  this.setState({...filterState, ...actionFun});
 }
 render(){
  return <Component {...this.state} />
 }
 }
}

五、redux API applyMiddleware 的實(shí)現(xiàn)

到此簡(jiǎn)化版的 react-redux 算是已經(jīng)初步完成,但是假如我們想要我們的 age 值的增長是一個(gè)異步操作,比如:通過按鈕點(diǎn)擊后經(jīng)過兩秒再修改 age ,而不是一點(diǎn)擊按鈕就立即修改值;這樣我們又該怎么實(shí)現(xiàn)呢?

當(dāng)然我們可以通過 setTimeout 兩秒后再執(zhí)行 action 創(chuàng)建函數(shù),比如這樣:

onClick = () => {
 setTimeout(()=>{
  // 兩秒后執(zhí)行 action 創(chuàng)建函數(shù)
  this.props.changeAge();
 }, 2000);
}

但是呢事實(shí)上我們并不愿意像上面那么整,我們想要這么一種效果:我們只需要簡(jiǎn)單的調(diào)用 action 創(chuàng)建函數(shù)即可實(shí)現(xiàn)異步操作,而不是需要進(jìn)行額外的操作;這時(shí)我們就需要為我們的 react-redux 編寫一個(gè)中間件來實(shí)現(xiàn)這么一個(gè)效果;

5.1 準(zhǔn)備工作

新增action 創(chuàng)建函數(shù)

  在這之前我們所有的 acton 創(chuàng)建函數(shù)都是直接返回一個(gè) action 對(duì)象,下面我們寫一個(gè)不一樣的 action 創(chuàng)建函數(shù), 它返回的不再是一個(gè) action 對(duì)象而是一個(gè)函數(shù),并且該函數(shù)接收兩個(gè)參數(shù) dispatch 以及 getState, 在該函數(shù)內(nèi)部我們進(jìn)行相應(yīng)的異步操作,比如:修改 age 值;

// actionCreate.js
export const asyncChangeAge = () => {
 // 返回函數(shù)
 return (dispatch, getState) => {
 setTimeout(v=>{
  console.log('==>', getState());
  dispatch({type: 'AGE_GROW'});
 }, 1000);
 }
}
修改頁面:新增按鈕并綁定點(diǎn)擊事件,并且調(diào)用 asyncChangeAge 函數(shù);
// Demo.jsx
// Demo.jsx
import React from 'react';
import './style.css';
// 導(dǎo)入 asyncChangeAge
import { changeAge, changeUser, asyncChangeAge } from './actionCreate';
import { connect } from './react-redux';

const mapStateToProps = (state) => {
 return {user: state.user, age: state.age};
}

// 添加 asyncChangeAge
@connect(mapStateToProps, {changeAge, changeUser, asyncChangeAge})
export default class Demo extends React.Component{
 onChange = (e) => {
 this.props.changeUser(e.target.value);
 }
 onClick = () => {
  this.props.changeAge();
 }
 // 點(diǎn)擊事件
 onClickAsync = () => {
 this.props.asyncChangeAge();
 }
 render(){
 return (
  <div>
  <p>user: {this.props.user}, age: {this.props.age}</p>
  user: 
  <input type="text" className="input" onChange={this.onChange}/>
  &nbsp;
  <button className="btn" onClick={this.onClick}>年齡增長</button>
  {/* 新增按鈕 */}
  <button className="btn" onClick={this.onClickAsync}>
   異步增長
  </button>
  </div>
 );
 }
}
頁面的變化其實(shí)很簡(jiǎn)單就是新增了一個(gè)按鈕:

5.2 需求實(shí)現(xiàn)

接下來我們先什么都不考慮先來實(shí)現(xiàn)我們的需求,現(xiàn)在 action 創(chuàng)建函數(shù) asyncChangeAge 因?yàn)榉祷氐氖且粋€(gè)對(duì)象,其 type 值為 undefined 所以當(dāng)我們點(diǎn)擊按鈕時(shí) reducer 將會(huì)一直匹配到默認(rèn)情況,返回的將是當(dāng)前的狀態(tài),接下來我們先讓我們的 action 創(chuàng)建函數(shù) asyncChangeAge 生效,達(dá)到異步修改狀態(tài)的作用;

擴(kuò)展 createStore

既然 asyncChangeAge 返回的不再是一個(gè) action 對(duì)象,而是一個(gè)函數(shù);那么其實(shí)我們要做的事情是很簡(jiǎn)單的,我們只需要針對(duì) createStore 中的返回值 dispatch 進(jìn)行一個(gè)簡(jiǎn)單的擴(kuò)展即可;通過判斷 dispatch 中的 action 參數(shù)是否是函數(shù)而進(jìn)行不同的操作:

// redux.js
export const createStore = (reducer) => {
 ......
 // 在createStore 我們對(duì)返回值 dispatch 進(jìn)行了封裝
 const dispatchExtend = (action) => {
 if(typeof action === 'function'){
  // action 為函數(shù),執(zhí)行函數(shù)
  action(dispatch, getState);
 } else {
  // action 為非函數(shù)(對(duì)象)調(diào)用dispatch
  dispatch(action);
 }
 }
 return {getState, dispatch: dispatchExtend, subscribe};
}

5.3 抽離封裝

上文我們通過對(duì) createStore 的返回值 dispatch 進(jìn)行了擴(kuò)展,實(shí)現(xiàn)了 redux-react 的異步操作,但問題是我們將代碼寫死在 createStore 中了,redux-react 的異步操作應(yīng)該是一個(gè)可選項(xiàng)而不應(yīng)該是必選項(xiàng);

重新擴(kuò)展 createStore :

新增參數(shù) middleware (函數(shù)), 在函數(shù) createStore 開始位置判斷 middleware 是否存在,存在則執(zhí)行;

// redux.js
export const createStore = (reducer, middleware) => {
 // 判斷 middleware 是否存在,存在則執(zhí)行
 if(middleware){
 return middleware(createStore)(reducer);
 }

 let state;
 const listeners = [];

 const getState = () => {
 return state;
 }

 const dispatch = (action) => {
 state = reducer(state, action);
 listeners.forEach(v => v());
 }

 const subscribe = (listener) => {
 listeners.push(listener);
 }

 dispatch({type: '%$&HJKAJJHDJHJ'});

 return {getState, dispatch, subscribe};
}
編寫函數(shù) applyMiddleware ,在創(chuàng)建 store 時(shí) 作為 createStore 第二參數(shù)
// App.js
const applyMiddleware = (createStore) => (redux)=> {
 // 在這里進(jìn)行創(chuàng)建 store
 const store = createStore(redux);
 // 返回store
 return {...store}
}

const store = createStore(reducer, applyMiddleware);
在 applyMiddleware 函數(shù)內(nèi)擴(kuò)展 dispatch

上文 applyMiddleware 函數(shù)并其實(shí)沒做任何事情, 只是在 createStore 函數(shù)外面套了一層函數(shù),那么接下來我們做點(diǎn)正事,來擴(kuò)展一下我們的 dispatch

// App.js
const applyMiddleware = (createStore) => (redux)=> {
 const store = createStore(redux);

 const midApi = {
 getState: store.getState,
 dispatch: (...args) => {dispatch(...args);}
 };

 const dispatch = (action) => {
 if( typeof action === 'function' ){
  action(midApi.dispatch, midApi.getState);
 } else {
  store.dispatch(action);
 }
 }

 return {
 ...store,
 dispatch
 };
}

5.4 擴(kuò)展分離

上文已經(jīng)實(shí)現(xiàn)了我們想要的效果了,我們?cè)?applyMiddleware 對(duì) dispatch 進(jìn)行了擴(kuò)展;然而我們是那么容易滿足的嘛,當(dāng)然不是的??! applyMiddleware 中對(duì) dispatch 的擴(kuò)展我們還可以將其單獨(dú)提出來封裝成一個(gè)函數(shù);

重寫 applyMiddleware ,再給 applyMiddleware 包裹一層函數(shù): 將對(duì) dispatch 的擴(kuò)展抽離,封裝成方法;
// App.js
const applyMiddleware = (middleware) => (createStore) => (redux)=> {
 const store = createStore(redux);

 const midApi = {
 getState: store.getState,
 dispatch: (...args) => {dispatch(...args);}
 };

 const dispatch = middleware(midApi)(store.dispatch);

 return {
 ...store,
 dispatch
 };
}
thunk 中間件: 其實(shí) thunk 才是真正的中間件;applyMiddleware 只是用來綁定中間件的
// App.js 
const thunk = ({dispatch, getState}) => next => (action) => {
 if(typeof action === 'function'){
 action(dispatch, getState);
 } else {
 next(action);
 }
}; 
在調(diào)用 createStore 時(shí)綁定中間件 thunk
// App.jsx
const store = createStore(reducer, applyMiddleware(thunk));

5.5 代碼整理

這一步只是將 applyMiddleware 函數(shù)移到 redux.js 文件中;同時(shí)將 thunk 函數(shù)寫到文件 thunk.jsx 中,然后在 App.js 中引用 applyMiddleware 以及 thunk 而已;

看下最終效果(效果和上一個(gè)錄屏是一樣樣的)

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • ReactNative列表ListView的用法

    ReactNative列表ListView的用法

    本篇文章主要介紹了ReactNative列表ListView的用法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • React路由封裝的實(shí)現(xiàn)淺析

    React路由封裝的實(shí)現(xiàn)淺析

    路由是React項(xiàng)目中相當(dāng)重要的概念,對(duì)于功能較為復(fù)雜的網(wǎng)頁來說,必然會(huì)涉及到不同功能間的頁面跳轉(zhuǎn),本篇文章將對(duì)React官方維護(hù)的路由庫React-Router-Dom的使用和常用組件進(jìn)行講解,同時(shí)對(duì)路由組件傳遞param參數(shù)的方式進(jìn)行講解,希望對(duì)各位讀者有所參考
    2022-08-08
  • React代碼分割的實(shí)現(xiàn)方法介紹

    React代碼分割的實(shí)現(xiàn)方法介紹

    雖然一直有做react相關(guān)的優(yōu)化,按需加載、dll 分離、服務(wù)端渲染,但是從來沒有從路由代碼分割這一塊入手過,所以下面這篇文章主要給大家介紹了關(guān)于React中代碼分割的方式,需要的朋友可以參考下
    2022-12-12
  • react實(shí)現(xiàn)記錄拖動(dòng)排序

    react實(shí)現(xiàn)記錄拖動(dòng)排序

    這篇文章主要介紹了react實(shí)現(xiàn)記錄拖動(dòng)排序的相關(guān)資料,需要的朋友可以參考下
    2023-07-07
  • react四種組件中DOM樣式設(shè)置方式詳解

    react四種組件中DOM樣式設(shè)置方式詳解

    這篇文章主要介紹了react之四種組件中DOM樣式設(shè)置方式,通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10
  • React-RouterV6+AntdV4實(shí)現(xiàn)Menu菜單路由跳轉(zhuǎn)的方法

    React-RouterV6+AntdV4實(shí)現(xiàn)Menu菜單路由跳轉(zhuǎn)的方法

    這篇文章主要介紹了React-RouterV6+AntdV4實(shí)現(xiàn)Menu菜單路由跳轉(zhuǎn),主要有兩種跳轉(zhuǎn)方式一種是編程式跳轉(zhuǎn)另一種是NavLink鏈接式跳轉(zhuǎn),每種方式通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • React中的refs的使用教程

    React中的refs的使用教程

    本篇文章主要介紹了React中的refs的使用教程,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-02-02
  • React18從0實(shí)現(xiàn)dispatch?update流程

    React18從0實(shí)現(xiàn)dispatch?update流程

    這篇文章主要為大家介紹了React18從0實(shí)現(xiàn)dispatch?update流程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • react封裝Dialog彈框的方法

    react封裝Dialog彈框的方法

    這篇文章主要為大家詳細(xì)介紹了react封裝Dialog彈框的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • React Native 搭建開發(fā)環(huán)境的方法步驟

    React Native 搭建開發(fā)環(huán)境的方法步驟

    本篇文章主要介紹了React Native 搭建開發(fā)環(huán)境的方法步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10

最新評(píng)論