使用 Redux 中间件保持用户界面整洁

使用 Redux 中间件保持用户界面整洁

原文:https://medium.com/hackernoon/keep-your-ui-clean-with-redux-middleware-752383016c50

Bob 叔叔开创性的 Clean Architecture 帖子激励了许多软件设计师,随着 JavaScript 允许业务逻辑代码被重用,它变得越来越重要。从来没有借口将业务逻辑分散到整个代码库中,但是现在我们甚至可以在需要的任何地方使用npm publish core-logicnpm install --save core-logic来减少

本文以 Bob 叔叔定义的用例为出发点:

这一层中的软件包含应用特定的业务规则。它封装并实现了系统的所有用例。这些用例编排了实体之间的数据流,并指导这些实体使用它们的企业级业务规则来实现用例的目标。

用例通常被描述为:

  • 贴一张我可爱的猫的图片;或者
  • 获取 J.R. Bookwalter 制作的电影列表

然而,软件是混乱的,抽象是有漏洞的,如果你和我一样,你经常会发现自己在幻想失控的利维坦用例,或者你已经将逻辑编码到 UI 中并且不会很快删除的琐碎用例。

下面我想为大叔呈现的是一些唾手可得的水果——用中间件来浮动你的 Redux 应用。Redux 是一个简单的 JavaScript 状态容器,它已经成为一种模式,在 Kotlin 和 Swift T21 的库中重现。我强烈建议你使用它——将它引入你的应用程序是微不足道的,在用 redux 状态工作 10 分钟后,你会爱上它,再也不会回头。

激励示例—登录屏幕

作为一个激励性的例子,我将使用实际应用这种模式的 Meeshkan 登录屏幕。顺便说一句,整个应用程序都应用了这种模式,所以如果你想知道某些事情是如何完成的,请随意下载,四处看看,并联系我们。

让我们从这个登录屏幕的简化版本开始:

// login.js
import React from 'react';
import { reduxForm, Field } from 'redux-form';
import { connect } from 'react-redux';
import { Button, MyTextComponent } from 'ui-lib';
import { Text, Alert } from 'react-native';
import Actions from 'react-native-router-flux';
import analytics from 'analytics-lib';
import { login } from 'kludgy-implementation';const onSuccess = () => {
  analytics.report('successfully logged in');
  Actions.main(); // this is our navigation action
}const onFailure = () => {
  analytics.report('log in error');
  Alert.alert("Sorry...", "Something went wrong");
}const submitter = ({email, password}) =>
  login(email, password, onSuccess, onFailure);const LogIn = ({handleSubmit}) => (
  <View>
    <Field component={MyTextComponent} name="email" />
    <Field component={MyTextComponent} name="password" />
    <Button onPress={handleSubmit(submitter)}>
      <Text>Log In</Text>
    </Button>
  </View>);export default connect()(reduxForm({form: 'LogIn'})(LogIn));

这种实现有几个问题:

  • 我们的login函数必须冒泡到 UI 来接受成功和失败的回调。如果我们想改变登录过程中的步骤数量,或者添加除成功和失败之外的更多选项,该怎么办?重构厄运…
  • 我们的分析函数也是如此,更糟糕的是,我们现在必须测试每个组件是否正确调用它。真是一团糟!
  • 我们必须记住成功和失败的顺序,以及它为什么/如何重要,在整个 UI 中散布逻辑,而没有任何规范告诉我们为什么会这样。
  • 当我们想改变导航、分析或提醒库的时候,我们就要对每个 UI 组件进行为期一周的重构。你好微妙的代码破损。

中间件拯救世界!

让我们用中间件重写上面的例子。首先,我将直接展示我们改进后的新组件:

// login.js
import React from 'react';
import { reduxForm, Field } from 'redux-form';
import { connect } from 'react-redux';
import { Button, MyTextComponent } from 'ui-lib';
import { Text} from 'react-native';
import { loginAction } from 'better-implementation';
import Ize, { navSuccessIze, alertIze, alertFailureIze } from 'ize';const login = Ize(
  loginAction,
  navSuccessIze('main'),
  analyticsIze(),
  alertFailureIze("Sorry...", Something went wrong")
);const LogIn = ({handleSubmit, login}) => (
  <View>
    <Field component={MyTextComponent} name="email" />
    <Field component={MyTextComponent} name="password" />
    <Button onPress={handleSubmit(login)}>
      <Text>Log In</Text>
    </Button>
  </View>);export default connect(null, {
  login
})(reduxForm({form: 'LogIn'})(LogIn));

一些值得庆祝的理由:

  • 导航或分析等对库的显式调用不复存在!
  • onSuccessonFailure回调中散布逻辑已经一去不复返了,我们无法在不触发各种副作用的情况下进行单元测试!
  • 这要短得多。
  • 这更容易阅读!
  • 这更容易测试!

好的,但是我们如何通过中间件实现呢?

1.通过 Ize 模式使用动作创建者

我们使用[redux-ize](https://www.npmjs.com/package/redux-ize)来实现 Action Creator Creator 模式。基本上,所有这些Ize的东西都采取了行动,为中间件添加了一堆有用的元数据。

2.使用像 redux saga 这样的库来处理异步调用

查看[redux-saga](https://redux-saga.js.org/)以了解如何处理我们的异步登录呼叫和调度成功或失败事件。举个例子:

import { call, put } from 'redux-saga';
import { loginSuccessAction, loginFailureAction } from 'actions';
import Ize, { navIze, alertIze } from 'ize';function* logInSideEffect({
  payload: {email, password},
  meta: {navSuccess, alertFailure}
}) {
  try {
    call(login, email, password);
    put(Ize(loginSuccessAction, navIze(navSuccess)));
  } catch(e) {
    put(Ize(loginFailureAction, alertIze(alertFailure)));
  }
}

注意我们如何再次使用ize模式将navSuccessalertFailure信息移动到正常的navalert轨道。这将确保当成功或失败动作被分派时,它被中间件拾取。

3.创建一些中间件来处理分析、导航和警报

像星期天早上一样简单…

// analytics.js
import analytics from 'my-awesome-analytics-provider';export default store => next => action => {
  action.meta && action.meta.analytics && analytics(action.type);    
  next(action);
}// nav.js
import Actions from 'react-native-router-flux';export default store => next => action => {
  action.meta && action.meta.nav && Actions[action.meta.nav]();  
  next(action);
}// alert.js
import Alert from 'react-native';export default store => next => action => {
  action.meta &&
    action.meta.alert &&
    Alert.alert(...action.meta.alert); 
  next(action);
}

我们有更多的理由庆祝!

  • 想改变你的分析提供商?没问题—两行代码。
  • 想要测试您的中间件吗?没问题—在一个地方使用一个sinon短截线。
  • 想根据应用程序的状态关闭某些导航或提醒吗?你现在可以进入商店了!
  • 想测试所有这些东西的顺序吗?没问题——只需编写一个测试来验证您的 redux store 配置。

总而言之——Redux 不仅仅是一个状态容器

Redux 将自己标榜为“JavaScript 应用的可预测状态容器”这是真的,但是有一点你会注意到,我没有提到一个将这些动作传播到一个状态的 reducer。当然,这些动作可以绑定到一个状态,实际上通常都是这样,但是我想保持简单,这样你就可以看到中间件有多强大。

很容易开始使用 Redux 中间件(或任何中间件,如组合 Rx 对象转换)来处理导航、分析和警报等事情。你的应用更可预测,更少的编码工作,更容易测试,更容易阅读,最重要的是,非常干净。谁不想这样呢?谢谢鲍勃叔叔!


本站为非盈利网站,作品由网友提供上传,如无意中有侵犯您的版权,请联系删除