redux 函数式组件_从Redux学习函数式编程设计

redux 函数式组件

Before I set my eyes on the Redux source code, I naively thought OOP is superior than FP(Functional Programming) as a programming paradigm. But this is not right. As we know that FP is dedicated to forming a easy to understand and clear workflow without those obscure abstracted objects and relations. It’s much closer to human’s procedural mode of thinking.

在着眼于Redux源代码之前,我天真的以为OOP优于FP(功能性编程)作为编程范例。 但这是不对的。 众所周知,FP致力于形成一个易于理解和清晰的工作流,而没有那些晦涩的抽象对象和关系。 它更接近于人类的程序思维方式。

Visit Pitayan.com to read the original article.

访问Pitayan.com以阅读原始文章。

Now React has already got hooks which can handle the "states" properly event without Redux. The demand for Redux could be declining but its code base is still worth learning. Especially for those who wants to enlighten themselves in functional programming. So, I guess it's never a bad idea to learn from a good example even though it is "obsolete" (not at all).

现在, React已经有了钩子,可以在没有Redux的情况下正确处理“状态”事件。 对Redux的需求可能会下降,但是其代码库仍然值得学习。 特别是对于那些希望在函数式编程中有所启发的人。 因此,我想从一个好的例子中学习,即使它已经“过时了”(一点也不没有),这绝不是一个坏主意。

When I started reading the Redux source code, I immediately felt the power of this unfamiliar usage of my familiar programming language. It feels like exploring an acient cave with a torch lighting up the paintings and found the great secret.

当我开始阅读Redux源代码时,我立即感受到了我熟悉的编程语言的这种陌生用法的力量。 感觉就像是用火把照亮一个古老的山洞,照亮了画作,并找到了伟大的秘密。

In order to know more about what Redux benefits from FP, I researched the Reduxsource code and created a mini version of it.

为了更多地了解Redux从FP中获得的好处,我研究了Redux源代码并创建了它的迷你版本。

Never be afraid of reinventing the wheel.

永远不要害怕重新发明轮子。

回顾Redux的工作原理 (Recap How Redux Works)

There are 4 basic key points for Redux:

Redux有4个基本要点:

  1. Create a store for data and let the view subscribe to it

    创建数据存储并让视图订阅
  2. The view dispatches an action to submit the changs

    视图派遣一个动作来提交变更
  3. The reducer changes the state based on the action type

    减速器根据动作类型改变状态
  4. Finally return the new state and triggers the view to change

    最后返回新状态并触发视图更改

This is the classic diagram explaining how Redux works:

这是解释Redux如何工作的经典图表:

Image for post

From the diagram above, it’s easy to find the keywords: actionstorereducerviewsubscribe and dispatch. And the next is to handle the relations among these keywords.

在上图中,很容易找到关键字: actionstorereducerviewsubscribedispatch 。 接下来是处理这些关键字之间的关系。

Redux方法比较:FP与OOP (Redux Approach Comparison: FP vs OOP)

Example usage of Redux

Redux的用法示例

const store = createStore(
combineReducers({
one: oneReducer,
two: twoReducer
}),
applyMiddleware(ReduxThunk, ReduxLogger)
);

Imagine if we do this in OOP, it may look like this:

想象一下,如果我们在OOP中执行此操作,则可能看起来像这样:

(The following is just my imagination. Not how older Redux behaves)

(以下只是我的想象。不是老Redux的行为方式)

const store = new Store();
store.setReducers({
one: oneReducer,
two: twoReducer
});
store.setMiddlewares({
ReduxThunk,
ReduxLogger
});

So, what are the differences? Both are good approaches IMO.

那么,有什么区别呢? 两者都是IMO的好方法。

FP does a good job on combining the functions together without side-effects. The return value is consistent which made the program returnings foreseeable during or after the execution.

FP在将功能组合在一起而没有副作用方面做得很好。 返回值是一致的,这使得在执行期间或执行之后可以预见程序的返回。

OOP made a solid structure which defined all the attributes a data model should contain. It makes it easy to modify or configure the data model.

OOP建立了一个坚实的结构,该结构定义了数据模型应包含的所有属性。 它使修改或配置数据模型变得容易。

In Redux, the reduers and middlewares are usually defined only once. It means, we don't need the ability to update these properties and we don't hope them to be altered during the runtime. As for FP approach, it utilizes the closure technique that kills the possbility of exposing the internal properties. With some fantastic FP techniques (curry, compose, pipe), it's even making the program much more human-readable than OOP.

Redux中reduersmiddlewares通常只定义一次。 这意味着,我们不需要更新这些属性的能力,也不希望在运行时对其进行更改。 至于FP方法,它利用closure技术来消除暴露内部特性的可能性。 借助一些出色的FP技术(curry,compose,pipe),它甚至使程序比OOP更具可读性。

I would say FP should be the best fit for such scenario. Of course, the FP I’m talking about here is far from the real functional programming like Haskell. But at least the idea of utilizing FP techniques in Javascript is something to follow.

我想说FP应该最适合这种情况。 当然,我在这里谈论的FP与真正的函数式编程(例如Haskell)相去甚远。 但是至少可以遵循在Javascript中使用FP技术的想法。

Image for post

出色的Redux FP设计 (Wonderful Redux FP Design)

In Redux, there is no class at all (In the earlier versions, it was once based on Class). All of its core APIs return either value or function (function factory). And this is exactly what FP expects a function to behave:

在Redux中,根本没有类(在早期版本中,它曾经是基于Class )。 其所有核心API均返回值或函数(函数工厂)。 这正是FP希望函数起作用的内容:

Pure with no side effects.

纯净,无副作用。

  • createStore: returns new Object { getState, dispatch, subscribe }

    createStore:返回新Object {getState,dispatch,subscribe}

  • combineReducers: returns new Function

    CombineReducers:返回新Function

  • applyMiddleware: returns new Function

    applyMiddleware:返回新Function

To explain the Redux design in an easy way, I implemented only the very core part of the APIs above. Since the latest version’s core concept hasn’t changed much, I wrote the source code based on very primitive version of Redux v1.0.1. Because I believe the very first related version would be the most comprehensive one to look at.

为了方便地解释Redux设计,我仅实现了上述API的核心部分。 由于最新版本的核心概念没有太大变化,因此我基于非常原始的Redux v1.0.1编写了源代码。 因为我相信第一个相关版本将是最全面的版本。

Let’s have a look.

我们来看一下。

createStore (createStore)

createStore defines those APIs that can be used within components. It's more like setter and getter

createStore定义了可以在组件内使用的那些API。 更像是settergetter

  • getState

    getState
  • dispatch

    调度
  • subscribe

    订阅
export default function createStore (reducer, enhancer) {
if (enhancer) {
return enhancer(createStore)(reducer);
} let currentState;
// Redux now uses a shallow copy `nextListeners` via `ensureCanMutateNextListeners()`
// to prevent bugs in the middle of `dispatch`
let currentListeners = []; function getState () {
return currentState;
} // Register callbacks to execute after changes
function subscribe (listener) {
currentListeners.push(listener); return () => {
// empty listeners
const index = currentListeners.indexOf(listener);
currentListeners.splice(index, 1);
};
} function dispatch (action) {
currentState = reducer(currentState, action);
// state changes, notify to invoke callbacks
currentListeners.forEach(listener => listener());
} // Initialize Redux by calling a virtual reducer
dispatch({ type: "MY-MINI-REDUX" }); return {
getState,
dispatch,
subscribe
};
}

CombineReducers (combineReducers)

Returns a new function that can return the new state. Can’t be any purer.

返回可以返回新状态的新函数。 不能纯洁。

// This is just a helper function to map through the Object
function mapValues(obj, fn) {
return Object.keys(obj).reduce((result, key) => {
result[key] = fn(obj[key], key);
return result;
}, {});
}export default function combineReducers (reducers) {
return function combination (state = {}, action) {
// Official Redux uses `pick` on filtering reducers.
// Let's trust reducers are functions here
return mapValues(reducers, (reducer, key) => reducer(state[key], action))
};
}

applyMiddleware (applyMiddleware)

I personally think the applyMiddleware API is the most amazing part of Redux. It provides an optimal solution to apply 3rd party plugins.

我个人认为applyMiddleware API是Redux最神奇的部分。 它提供了应用第三方插件的最佳解决方案。

The FP compose in the source code is corresponding to Math's associative law in my understanding.

该FP compose的源代码对应于数学的结合律在我的理解。

( x ∗ ( yz ) ) = xyz

( x *( y * z ))= x * y * z

The usage of applyMiddleware is actually a form of a pipe that allows us to inject enhancement functions that returns the store Object. It's pretty similar to Aspect Oriented Programming which the most typical example is the annotation / decorator.

applyMiddleware的用法实际上是pipe一种形式,它使我们可以注入增强功能以​​返回存储对象。 它与Aspect Oriented Programming非常相似,后者最典型的示例是注释/装饰器。

// Combine the functions
// a(b(c())) => compose(a, b, c)
function compose(...funcs) {
return funcs.reduceRight((composed, f) => f(composed));
}export default function applyMiddleware(...middlewares) {
return next => (reducer, initialState) => {
const store = next(reducer, initialState);
let dispatch = store.dispatch;
const middlewareAPI = {
getState: store.getState,
dispatch: action => dispatch(action)
};
const chain = middlewares.map(middleware => middleware(middlewareAPI)); // Enhance the `dispatchers` by applying middlewares to each of them
dispatch = compose(...chain, store.dispatch); return {
...store,
dispatch
};
};
}

Redux中间件 (Redux Middlewares)

There are some famous middlewares for Redux like redux-thunk and [redux-logger(https://github.com/LogRocket/redux-logger). These are the good examples using applyMiddleware API to enhance the functionalities. Furthermore, their code base is astonishingly small. The core part has only a few lines of code.

Redux有一些著名的中间件,例如redux-thunk和[redux-logger( https://github.com/LogRocket/redux-logger )。 这些是使用applyMiddleware API增强功能的好例子。 此外,它们的代码库非常小。 核心部分只有几行代码。

All of the middlewares are curry functions.

所有的中间件都是curry函数。

funcA => funcB => funcC

funcA => funcB => funcC

funcB = funcA()

funcB = funcA()

funcC = funcB()

funcC = funcB()

This is extremly helpful when I need other contexts to use within the code block. As of the examples, it’s easy to find that next and action are passed in as context to help handle some complex cases.

当我需要在代码块中使用其他上下文时,这非常有用。 在示例中,很容易发现将nextaction作为上下文传递来帮助处理一些复杂的情况。

Redux Thunk (Redux Thunk)

redux-thunk allows to use function as dispatch parameter so that I could do something right before "dispatching".

redux-thunk允许使用函数作为dispatch参数,这样我就可以在“调度”之前做一些事情。

// without redux-thunk
dispatch({ type: 'action', payload: 'value' })// with redux-thunk
// the dispatch is wrapped up by a new function
dispatch(function (dispatch, getState) {
console.log('redux-thunk')
dispatch({ type: 'action', payload: 'value' })
})

Here is the core:

这是核心:

// Allow passing function to dispatch
export default function thunk({ dispatch, getState }) {
return next => action => {
if (typeof action === "function") {
return action(dispatch, getState);
} return next(action);
};
}

Redux记录器 (Redux Logger)

It’s easy to guess what this middleware does. It simply outputs the state changes.

很容易猜出该中间件的功能。 它仅输出状态更改。

// Output the previous and current state in console
export default function logger({ getState }) {
return next => action => {
console.log("======== Redux Logger ========");
console.log("Action Type: ", action.type);
const prevState = getState();
console.log("Prev: ", prevState); const returnValue = next(action); const nextState = getState();
console.log("Next: ", nextState);
console.log("==============================");
return returnValue;
};
}

演示应用 (A demo app)

I implemented mini version of redux and a small counter application to demostrate the functions. The application will do four arithmetic operations: plus, minus, multiply and divide. The number will change after clicking the operation button. Meanwhile, multiply and divide will have 300ms' delay which is enabled by a custom middleware (a mini redux-thunk).

我实现了Redux的迷你版和一个小型计数器应用程序以演示这些功能。 该应用程序将执行四个算术运算:加,减,乘和除。 单击操作按钮后,数字将更改。 同时, multiplydivide将具有300ms的延迟,这是通过自定义中间件(小型redux-thunk)启用的。

Repository link of “mini-redux”:

“ mini-redux”的存储库链接:

https://github.com/daiyanze/mini-redux

https://github.com/daiyanze/mini-redux

Demo App link:

演示应用链接:

https://daiyanze.com/mini-redux/build/index.html

https://daiyanze.com/mini-redux/build/index.html

Image for post

The app has one child component: MiniReduxComp. In my mini-redux, I didn't create a context provider to trigger updates. Instead, I subscribe to the store changes within the component and do forceUpdate to react to changes.

该应用程序具有一个子组件: MiniReduxComp 。 在我的迷你Redux中,我没有创建上下文提供程序来触发更新。 相反,我订阅了组件内的存储更改,并执行forceUpdate对更改做出React。

I also applied the custom middlewares redux-thunk and redux-logger to enrich the functions.

我还应用了定制的中间件redux-thunkredux-logger以丰富功能。

import React, { Component } from 'react';
import store from '../store'export default class MiniReduxComp extends Component { componentDidMount() {
this.unsubscribe = store.subscribe(() => this.forceUpdate());
} componentWillUnmount() {
this.unsubscribe && this.unsubscribe();
} plus = () => store.dispatch({ type: "PLUS" }) minus = () => store.dispatch({ type: 'MINUS' }) multiply = () => store.dispatch((dispatch, getState) => {
setTimeout(() => {
dispatch({ type: 'MULTIPLY' })
}, 300)
}) divide = () => store.dispatch((dispatch, getState) => {
setTimeout(() => {
dispatch({ type: 'DIVIDE' })
}, 300)
}) render() {
return (
<div>
<h4>Plus / Minus 1</h4> <p>{store.getState().count}</p> <button onClick={this.plus}>+1</button>
<button onClick={this.minus}>-1</button> <br />
<br /> <h4>Multiply / Divide 2 (0.3s delay)</h4>
<p>{store.getState().double}</p> <button onClick={this.multiply}>x2</button>
<button onClick={this.divide}>/2</button>
</div>
);
}
}

结论 (Conclusion)

I think in modern web development, OOP is still the mainstream. Yet we could see that there are some open source projects mix the programming paradigms and deliver very qualified frameworks (e.g. nest.js). Thanks to React communities, FP is part of development necessities now.

我认为在现代Web开发中,OOP仍然是主流。 但是我们可以看到,有一些开源项目混合了编程范例并提供了非常合格的框架(例如nest.js )。 由于有React社区,FP现在已成为开发必需品的一部分。

Okay, that’s all for the Redux drill-down. Hope you also get a good understanding about the FP designs in Redux. If you think this article is great, please share it on social networks.

好的,这就是Redux深入分析的全部内容。 希望您也对Redux中的FP设计有一个很好的了解。 如果您认为这篇文章很棒,请在社交网络上分享。

Thank you reading!

谢谢阅读!

翻译自: https://medium.com/dev-genius/learn-fp-design-from-redux-95cc21479086

redux 函数式组件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值