为什么我们需要在Redux中将自定义中间件创建为咖喱函数

时间:2019-10-08 10:36:42

标签: reactjs redux

我是Redux的新手,正在学习如何为React应用程序创建中间件。我想问一个关于将自定义中间件创建为CURRIED函数的问题,那就是为什么会出现问题?在创建中间件的情况下,currying有什么好处?也就是说,为什么不写const middleware = store=>next=>action=>{}而不写const middleware = (store,next,action)=>{}

3 个答案:

答案 0 :(得分:0)

为什么要咖喱

实际上,Currying尝试将程序状态的更改次数减至最少 通过使用不可变数据和纯(无副作用)函数而称为副作用。当您要编写可轻松重用和配置的少量代码模块时,避免在部分应用程序中频繁调用具有相同参数的函数,则Currying很有帮助。

在中间件环境中进行curring的好处

通过使用currying,redux基本上为您提供了三个钩子函数:

  • const firstFunction = logger(store)
  • const secondFunction = firstFunction(next)
  • const thirdFunction = secondFunction(action)

现在,根据不同的情况,以上每个功能都有其自己的用途。 Store是在第一个功能中创建的,而第二个功能则为您提供了下一个中间件,而在第三个功能中,我们可以使用前一个中间件的结果操作来进行某些操作。

Redux的共同作者Dan Abramov也回答了这个问题。您可以检查他对此here

的想法

答案 1 :(得分:0)

这是因为compose的工作原理。

假设我有2个功能:plus2和times3,那么我可以将它们组合为:

const plus2Times3 = compose(plus2,times3);
plus2Times3(1);//(1+2)*3=9
plus2Times3(2);//(2+2)*3=12

comp2对plus2和times3的处理方式是:(...arg)=>times3(...plus2(...arg))

用简单的函数很难理解,但是使用咖喱函数呢?

所有中间件功能都具有相同的状态,因此,如果我有一系列中间件功能,我可以做到:

//middewares is [store=>next=>action=>next(action),store=>next=>action=>next(action)]
const mw = middlewares.map(fn=>fn({getState,dispatch}));
//mw is [next=>action=>next(action),next=>action=>next(action)]

现在我有一个next=>action=>next(action)的函数数组,其中下一个是执行操作的函数。

因此,如果我向next=>action=>next(action)提供下一个功能,则我得到的功能下一个功能:action=>does something。这意味着redux可以使用compose从一系列函数中创建一个函数:

const middeware = compose(middlewares.map(fn=>fn({getState,dispatch}));
//middeware is now next=>action=>do something
//redux can execute it with: middleware(reducer)(action)

Here是一个自写的redux与react-redux结合使用的示例,展示了如何使用compose从一系列中间件函数中创建一个函数。

以下代码演示了如何轻松地构成中间件功能:

//implementation of compose is very simple, I added taking
//  out anything that isn't a function
const compose = (...functions) => {
  return (
    functions
      //take out non functions
      .filter(e => typeof e === 'function')
      .reduce((result, fn) => {
        return (...args) => result(fn(...args));
      })
  );
};
const middeWares = [
  store => next => action => {
    console.log('1', action);
    next({ ...action, counter: action.counter + 1 });
  },
  store => next => action => {
    console.log('2', action);
    next({ ...action, counter: action.counter + 1 });
  },
  store => next => action => {
    console.log('3', action);
    next({ ...action, counter: action.counter + 1 });
  },
];
//just pass in 88 as store, we don't use store
const middleWare = compose(...middeWares.map(x => x(88)));

//executing the middleware
//pass in id function as next function (probably reducer in redux)
middleWare(x=>x)({counter:86});

Redux可以为中间件选择任何签名,只要它具有存储,下一步和操作即可。以下示例与上一个示例基本相同,但是将中间件功能映射到可以组成的对象:

const compose = (...functions) => {
  return (
    functions
      //take out non functions
      .filter(e => typeof e === 'function')
      .reduce((result, fn) => {
        return (...args) => result(fn(...args));
      })
  );
};
//middleware could also have (action,next,store) signature
const middeWares = [
  (action,next,store) => {
    console.log('1', action);
    next({ ...action, counter: action.counter + 1 });
  },
  (action,next,store) => {
    console.log('2', action);
    next({ ...action, counter: action.counter + 1 });
  },
  (action,next,store) => {
    console.log('3', action);
    next({ ...action, counter: action.counter + 1 });
  },
];
//using 88 for store, we can map the middleware to s=>n=>a=>...
const middleWare = compose(...middeWares.map(x => n=>a=>x(a,n,88)));
//pass in id function as next function (could be dispatch or reducer)
//  depending on how redux is written
middleWare(x=>x)({counter:86});

答案 2 :(得分:-1)

好的,我会尽力澄清您的困惑。 首先,我们了解中间件的目的

  

中间件是一些代码,您可以在接收代码的框架之间放置   请求,并生成响应的框架

由于currying允许您从另一个函数返回一个函数,因此您可以通过这种方式看到它,在将某些内容提取到框架之前,我们希望执行一些其他操作,因此,如您所建议的那样,您可以这样做

const middleware = (store,next,action)=>{}

我们直接调用框架代码,使用currying可以中断并完成我们的工作

希望有帮助