react中间件是什么?

在react中,中间件就是一个函数,对store.dispatch方法进行了改造,在发出Action和执行Reducer这两步之间,添加了其他功能;常用的中间件都有现成的,只要引用别人写好的模块即可。

react中间件是什么?

一、中间件的概念

为了理解中间件,让我们站在框架作者的角度思考问题:如果要添加功能,你会在哪个环节添加?

(1)Reducer:纯函数,只承担计算 State 的功能,不合适承担其他功能,也承担不了,因为理论上,纯函数不能进行读写操作。

(2)View:与 State 一一对应,可以看作 State 的视觉层,也不合适承担其他功能。

(3)Action:存放数据的对象,即消息的载体,只能被别人操作,自己不能进行任何操作。

想来想去,只有发送 Action 的这个步骤,即store.dispatch()方法,可以添加功能。举例来说,要添加日志功能,把 Action 和 State 打印出来,可以对store.dispatch进行如下改造。

let next = store.dispatch;store.dispatch = function dispatchAndLog(action) {  console.log('dispatching', action);  next(action);  console.log('next state', store.getState());}

登录后复制

上面代码中,对store.dispatch进行了重定义,在发送 Action 前后添加了打印功能。这就是中间件的雏形。

中间件就是一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能。常用的中间件都有现成的,只要引用别人写好的模块即可。

二、中间件的用法

本教程不涉及如何编写中间件,因为常用的中间件都有现成的,只要引用别人写好的模块即可。比如,上一节的日志中间件,就有现成的redux-logger模块。这里只介绍怎么使用中间件。

import { applyMiddleware, createStore } from 'redux';import createLogger from 'redux-logger';const logger = createLogger(); const store = createStore(  reducer,  applyMiddleware(logger));

登录后复制

上面代码中,redux-logger提供一个生成器createLogger,可以生成日志中间件logger。然后,将它放在applyMiddleware方法之中,传入createStore方法,就完成了store.dispatch()的功能增强。

这里有两点需要注意:

(1)createStore方法可以接受整个应用的初始状态作为参数,那样的话,applyMiddleware就是第三个参数了。

const store = createStore(  reducer,  initial_state,  applyMiddleware(logger));

登录后复制

(2)中间件的次序有讲究。

const store = createStore(  reducer,  applyMiddleware(thunk, promise, logger));

登录后复制

上面代码中,applyMiddleware方法的三个参数,就是三个中间件。有的中间件有次序要求,使用前要查一下文档。比如,logger就一定要放在最后,否则输出结果会不正确。

三、applyMiddlewares()

看到这里,你可能会问,applyMiddlewares这个方法到底是干什么的?

它是 Redux 的原生方法,作用是将所有中间件组成一个数组,依次执行。下面是它的源码。

export default function applyMiddleware(...middlewares) {  return (createStore) => (reducer, preloadedState, enhancer) => {    var store = createStore(reducer, preloadedState, enhancer);    var dispatch = store.dispatch;    var chain = [];     var middlewareAPI = {      getState: store.getState,      dispatch: (action) => dispatch(action)    };    chain = middlewares.map(middleware => middleware(middlewareAPI));    dispatch = compose(...chain)(store.dispatch);     return {...store, dispatch}  }}

登录后复制

上面代码中,所有中间件被放进了一个数组chain,然后嵌套执行,最后执行store.dispatch。可以看到,中间件内部(middlewareAPI)可以拿到getState和dispatch这两个方法。

四、异步操作的基本思路

理解了中间件以后,就可以处理异步操作了。

同步操作只要发出一种 Action 即可,异步操作的差别是它要发出三种 Action。

操作发起时的 Action

操作成功时的 Action

操作失败时的 Action

以向服务器取出数据为例,三种 Action 可以有两种不同的写法。

// 写法一:名称相同,参数不同{ type: 'FETCH_POSTS' }{ type: 'FETCH_POSTS', status: 'error', error: 'Oops' }{ type: 'FETCH_POSTS', status: 'success', response: { ... } }// 写法二:名称不同{ type: 'FETCH_POSTS_REQUEST' }{ type: 'FETCH_POSTS_FAILURE', error: 'Oops' }{ type: 'FETCH_POSTS_SUCCESS', response: { ... } }

登录后复制

除了 Action 种类不同,异步操作的 State 也要进行改造,反映不同的操作状态。下面是 State 的一个例子。

let state = {  // ...   isFetching: true,  didInvalidate: true,  lastUpdated: 'xxxxxxx'};

登录后复制

上面代码中,State 的属性isFetching表示是否在抓取数据。didInvalidate表示数据是否过时,lastUpdated表示上一次更新时间。

现在,整个异步操作的思路就很清楚了。

操作开始时,送出一个 Action,触发 State 更新为”正在操作”状态,View 重新渲染

操作结束后,再送出一个 Action,触发 State 更新为”操作结束”状态,View 再一次重新渲染

五、redux-thunk 中间件

异步操作至少要送出两个 Action:用户触发第一个 Action,这个跟同步操作一样,没有问题;如何才能在操作结束时,系统自动送出第二个 Action 呢?

奥妙就在 Action Creator 之中。

class AsyncApp extends Component {  componentDidMount() {    const { dispatch, selectedPost } = this.props    dispatch(fetchPosts(selectedPost))  }// ...

登录后复制

上面代码是一个异步组件的例子。加载成功后(componentDidMount方法),它送出了(dispatch方法)一个 Action,向服务器要求数据 fetchPosts(selectedSubreddit)。这里的fetchPosts就是 Action Creator。

下面就是fetchPosts的代码,关键之处就在里面。

react中间件是什么?

const fetchPosts = postTitle => (dispatch, getState) => {  dispatch(requestPosts(postTitle));  return fetch(`/some/API/${postTitle}.json`)    .then(response => response.json())    .then(json => dispatch(receivePosts(postTitle, json)));  };};// 使用方法一store.dispatch(fetchPosts('reactjs'));// 使用方法二store.dispatch(fetchPosts('reactjs')).then(() =>  console.log(store.getState()));

登录后复制

上面代码中,fetchPosts是一个Action Creator(动作生成器),返回一个函数。这个函数执行后,先发出一个Action(requestPosts(postTitle)),然后进行异步操作。拿到结果后,先将结果转成 JSON 格式,然后再发出一个 Action( receivePosts(postTitle, json))。

上面代码中,有几个地方需要注意。

(1)fetchPosts返回了一个函数,而普通的 Action Creator 默认返回一个对象。

(2)返回的函数的参数是dispatch和getState这两个 Redux 方法,普通的 Action Creator 的参数是 Action 的内容。

(3)在返回的函数之中,先发出一个 Action(requestPosts(postTitle)),表示操作开始。

(4)异步操作结束之后,再发出一个 Action(receivePosts(postTitle, json)),表示操作结束。

这样的处理,就解决了自动发送第二个 Action 的问题。但是,又带来了一个新的问题,Action 是由store.dispatch方法发送的。而store.dispatch方法正常情况下,参数只能是对象,不能是函数。

这时,就要使用中间件redux-thunk。

import { createStore, applyMiddleware } from 'redux';import thunk from 'redux-thunk';import reducer from './reducers';// Note: this API requires redux@>=3.1.0const store = createStore(  reducer,  applyMiddleware(thunk));

登录后复制

上面代码使用redux-thunk中间件,改造store.dispatch,使得后者可以接受函数作为参数。

因此,异步操作的第一种解决方案就是,写出一个返回函数的 Action Creator,然后使用redux-thunk中间件改造store.dispatch。

六、redux-promise 中间件

既然 Action Creator 可以返回函数,当然也可以返回其他值。另一种异步操作的解决方案,就是让 Action Creator 返回一个 Promise 对象。

这就需要使用redux-promise中间件。

import { createStore, applyMiddleware } from 'redux';import promiseMiddleware from 'redux-promise';import reducer from './reducers'; const store = createStore(  reducer,  applyMiddleware(promiseMiddleware));

登录后复制

这个中间件使得store.dispatch方法可以接受 Promise 对象作为参数。这时,Action Creator 有两种写法。写法一,返回值是一个 Promise 对象。

const fetchPosts =   (dispatch, postTitle) => new Promise(function (resolve, reject) {     dispatch(requestPosts(postTitle));     return fetch(`/some/API/${postTitle}.json`)       .then(response => {         type: 'FETCH_POSTS',         payload: response.json()       });});

登录后复制

写法二,Action 对象的payload属性是一个 Promise 对象。这需要从redux-actions模块引入createAction方法,并且写法也要变成下面这样。

import { createAction } from 'redux-actions'; class AsyncApp extends Component {  componentDidMount() {    const { dispatch, selectedPost } = this.props    // 发出同步 Action    dispatch(requestPosts(selectedPost));    // 发出异步 Action    dispatch(createAction(      'FETCH_POSTS',       fetch(`/some/API/${postTitle}.json`)        .then(response => response.json())    ));  }

登录后复制

上面代码中,第二个dispatch方法发出的是异步 Action,只有等到操作结束,这个 Action 才会实际发出。注意,createAction的第二个参数必须是一个 Promise 对象。

看一下redux-promise的源码,就会明白它内部是怎么操作的。

export default function promiseMiddleware({ dispatch }) {  return next => action => {    if (!isFSA(action)) {      return isPromise(action)        ? action.then(dispatch)        : next(action);    }     return isPromise(action.payload)      ? action.payload.then(          result => dispatch({ ...action, payload: result }),          error => {            dispatch({ ...action, payload: error, error: true });            return Promise.reject(error);          }        )      : next(action);  };}

登录后复制

从上面代码可以看出,如果 Action 本身是一个 Promise,它 resolve 以后的值应该是一个 Action 对象,会被dispatch方法送出(action.then(dispatch)),但 reject 以后不会有任何动作;如果 Action 对象的payload属性是一个 Promise 对象,那么无论 resolve 和 reject,dispatch方法都会发出 Action。

以上就是react中间件是什么?的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2721774.html

(0)
上一篇 2025年3月7日 22:48:24
下一篇 2025年3月7日 06:46:44

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • react怎么添加背景图片

    react添加背景图片的方法:首先引入我们需要的图片路径,如【import Background from ‘../../../images/xxx.jpg’】;然后定义背景样式,如【width: “100%”】;最…

    2025年3月7日
    200
  • React中Material-UI是什么

    React中Material-UI是一款React组件库来实现Google的Material Design风格UI界面框架,也是首个React的UI工具集之一,使用它可以快速搭建出赏心悦目的应用界面。 Material-UI是一款React…

    2025年3月7日
    200
  • react中如何引入插件

    react中引入插件的方法:首先在js库开头添加【(function(answerSheet){)】;然后在js库的尾部添加【})($); module.exports = $;】即可。 本文环境:windows10、react16,Del…

    2025年3月7日
    200
  • react中如何引入css样式

    react中引入css样式的方法:首先在render函数中声明样式,如【render() {let mystyle = {}}】;然后引用样式即可,如【return();】。 本文环境:windows10、react16&&…

    2025年3月7日
    200
  • react中的portal是做什么的

    react中的portal可以将子组件渲染到非父组件的子树下,同时父组件仍能对子组件做出反应;使用方法如【ReactDOM.createPortal(this.props.children, this.el);】。 本文环境:windows…

    2025年3月7日
    200
  • react组件有哪些阶段

    react组件有Initialization、Mounting、Updating、Unmounting和Error Handing等五个阶段。其中Error Handing阶段属于错误处理阶段。 本文环境:windows10、react16…

    2025年3月7日
    200
  • react中如何引入图片

    react中引入图片的方法:可以通过!important引入,如【import avatarSmall from ‘../…/assets/images/person/xxxjpg’】,然后在img中直接…

    2025年3月7日
    200
  • react和react native的区别是什么

    react和react native的区别是:1、框架作用的平台不同;2、工作原理有差别;3、渲染周期不同;4、react native中所有元素都会被平台指定的react组件替换;5、宿主平台的API不同。 本文环境:windows10、…

    2025年3月7日
    200
  • react状态机是什么

    react把组件看成是一个状态机,通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。 React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数…

    2025年3月7日
    200
  • react中如何引入样式

    react中引入样式的方法:1、模块样式,引入方式【import ‘./index.css’;】;2、行内样式,代码为【】。 相关学习推荐:react视频教程 本教程操作环境:windows7系统、React17版,…

    2025年3月7日
    200

发表回复

登录后才能评论