redux ngrx_另一个减少Redux(NGRX)应用程序样板的指南

redux ngrx

by Andrey Goncharov

通过安德烈·贡恰洛夫(Andrey Goncharov)

另一个减少Redux(NGRX)应用程序样板的指南 (Yet another guide to reduce boilerplate in your Redux (NGRX) app)

我们在这里要覆盖什么? (What are we gonna cover here?)

In this article, we’re gonna discuss several ways/tips/tricks/ancient black magic rituals to reduce boilerplate in our overwhelmed-with-boilerplate Redux (and NGRX!) apps. I’ve come up with these over the years from first-hand production experience.

在本文中,我们将讨论几种方法/技巧/技巧/古老的黑魔法仪式,以减少我们不堪重负的Redux(和NGRX!)应用程序中的样板。 这些年来,我已经从第一手生产经验中提出了这些建议。

Let me be honest with you all. I wanted to speak just about my new micro-library flux-action-class at first. But it seems like sometimes tech blogs look more and more like Twitter lately…and maybe you want some more meaningful long read. So I thought: “What the heck? I got some experience and best practices of my own which I spilled some sweat and blood over. Maybe, it could help some people out there. Maybe, people out there could help me to improve some of it.”

让我对你们所有人诚实。 首先,我只想谈谈我的新微库通量作用课程 。 但是似乎有时候高科技博客最近看起来越来越像Twitter……也许您想要一些更有意义的长期阅读。 所以我想:“到底是什么? 我获得了一些自己的经验和最佳实践,这让我不知所措。 也许,它可以帮助一些人。 也许,在那里的人可以帮助我改善其中的一些。”

识别样板 (Identifying boilerplate)

Let’s take a look at a typical example of how to make AJAX requests in Redux. In this particular case let’s imagine we wanna get a list of cats from the server.

让我们看一下如何在Redux中进行AJAX请求的典型示例。 在这种特殊情况下,让我们想象一下我们想要从服务器中获取猫的列表。

If you’re wondering why I have selector factories (makeSelector…) take a look here

如果您想知道为什么我有选择器工厂(makeSelector ...),请看这里

I’m leaving out side effect handling on purpose. It’s a topic for a whole different article full of teenager’s anger and criticism for the existing ecosystem :D

我没有故意处理副作用。 这是整个不同文章的主题,充满了青少年对现有生态系统的愤怒和批评:D

This code has several weak spots:

这段代码有几个弱点:

  • Action creators are unique objects themselves but we still need action types for serialization purposes. Could we do better?

    动作创建者本身就是唯一的对象,但是出于序列化的目的,我们仍然需要动作类型。 我们可以做得更好吗?
  • As we add entities we keep duplicating the same logic for flipping loading flag. Actual server data and the way we want to handle it may change, but logic for loading is always the same. Could we get rid of it?

    当我们添加实体时,我们将重复相同的逻辑以翻转loading标志。 实际的服务器数据以及我们要处理的数据方式可能会发生变化,但是loading逻辑始终是相同的。 我们可以摆脱它吗?

  • Switch statement is O(n) (which is not a solid argument by itself because Redux is not very performant anyway). Redux requires a couple extra lines of code for each case and switches can not be easily combined. Could we figure out something more performant and readable?

    Switch语句为O(n)(它本身不是一个可靠的参数,因为Redux并不是很有效)。 Redux在每种情况下都需要额外的几行代码,并且开关无法轻松组合。 我们能找出一些更高性能和可读性的东西吗?
  • Do we really need to keep an error for each entity separately?

    我们真的需要为每个实体单独保留一个错误吗?
  • Using selectors is a good idea. This way we have an abstraction over our store and can change its shape without breaking the whole app by just adjusting our selectors. Yet we have to create a factory for each selector due to how memoizaion works. Is there any other way?

    使用选择器是一个好主意。 这样,我们可以对商店进行抽象处理,并且可以通过调整选择器来更改其形状而不会破坏整个应用程序。 然而,由于记忆的工作原理,我们必须为每个选择器创建一个工厂。 还有其他办法吗?

提示1:摆脱动作类型 (Tip 1: Get rid of action types)

Well, not really. But we can make JS generate them for us!

好吧,不是真的。 但是我们可以让JS为我们生成它们!

Let’s take a minute here to think why we even need action types. Of course, to help the reducer somehow differentiate between incoming actions and change our state accordingly. But does it really have to be a string? If only we had a way to create objects (actions) of certain types… Classes to the rescue! We most definitely could use classes as action creators and do switch by type. Like this:

让我们在这里花点时间思考为什么我们甚至需要动作类型。 当然,为了帮助减速器以某种方式区分进来的动作并相应地更改我们的状态。 但这真的必须是字符串吗? 如果只有一种方法可以创建某些类型的对象(动作),那么就可以救援了! 我们绝对可以将类用作动作创建者,并按类型进行switch 。 像这样:

All good, but here’s a thing… We can no longer serialize and deserialize our actions. They are no longer simple objects with a prototype of Object. All have unique prototypes which actually makes switching over action.constructor work. Dang, I liked the idea of serializing my actions to a string and attaching it to bug reports. So could we do even better?

一切都很好,但是这里有件事……我们不能再序列化和反序列化我们的操作。 它们不再是带有对象原型的简单对象。 它们都有独特的原型,实际上使切换action.constructor起作用。 Dang,我喜欢将操作序列化为字符串并将其附加到错误报告的想法。 那我们还能做得更好吗?

Actually, yes! Luckily each class has a name, which is a string, and we could utilize them. So for the purposes of serialization, each action needs to be a simple object with field type (please, take a look here to learn what else any self-respecting action should have). We could add getter type to each one of our classes which would use class's name.

其实,是! 幸运的是,每个类都有一个名称,它是一个字符串,我们可以利用它们。 因此,出于序列化的目的,每个动作都必须是一个具有字段type的简单对象(请在这里看看,以了解其他任何自重动作应该具有的内容)。 我们可以将getter type添加到我们每个使用类名称的类中。

It would work, but this way we can not prefix our action types as this great proposal suggests (actually, I like its successor even more). To work around prefixing we should stop using class’ name directly and create another getter for it. This time a static one.

它将起作用,但是通过这种方式,我们不能像这个好建议所建议的那样在操作类型前加上前缀(实际上,我更喜欢它的后继者 )。 要解决前缀问题,我们应该停止直接使用类的名称,并为其创建另一个getter。 这次是静态的。

Let’s polish it a little to avoid code duplication and add one more assumption to reduce boilerplate even further. If action is an error action payload must be an instance of Error.

让我们对其进行完善,以避免代码重复,并增加一个假设以进一步减少样板。 如果action是一个错误操作,那么payload必须是Error一个实例。

At this point, it works perfectly with NGRX. Redux is complaining about dispatching non-plain objects (it validates the prototype chain). Fortunately, JS allows us to return an arbitrary value from the constructor and we do not really need our actions to have a prototype.

此时,它可以与NGRX完美配合。 Redux抱怨调度非普通对象(它验证了原型链)。 幸运的是,JS允许我们从构造函数中返回任意值,并且我们实际上不需要采取行动就可以拥有原型。

Not to make you guys copy-paste ActionStandard class and worry about its reliability, I created a small library called flux-action-class, which already has all that code covered with tests with 100% code coverage, written in TypeScript for TypeScript and JavaScript projects.

为了ActionStandard你们复制粘贴ActionStandard类并担心它的可靠性,我创建了一个名为flux-action-class的小型库 ,该库已经包含了用100%代码覆盖率进行测试的所有代码,并使用TypeScript为TypeScript和JavaScript编写项目。

提示2:组合减速机 (Tip 2: Combine your reducers)

The idea is simple: use combineReducers not only for top level reducers, but for combining reducers for loading and other stuff. Let the code speak for itself:

这个想法很简单:不仅可以将CombineReducers用于顶级减速器,而且可以将减速器组合用于loading和其他东西。 让代码说明一切:

提示3:切换开关 (Tip 3: Switch away from switch)

Use objects and pick from them by key instead! Picking a property of an object by key is O(1) and it looks much cleaner if you ask me. Like this:

使用对象并通过键从中选择! 通过键选择对象的属性为O(1),如果您问我,它看起来更干净。 像这样:

I suggest we refactor reducerLoading a little bit. With the introduction of reducer maps, it makes sense to return a reducer map from reducerLoading. We could extend it if needed (unlike switches).

我建议我们重构reducerLoading一点。 通过引入reducer映射,从reducerLoading返回一个reducer映射是reducerLoading 。 如果需要,我们可以扩展它(与开关不同)。

Redux’s official documentation mentions this, but for some reason, I saw lots of people still using switch-cases. There’s already a library for createReducer. Do not hesitate to use it.

Redux的官方文档中提到了这一点 ,但是由于某些原因,我看到很多人仍在使用开关盒。 已经有一个createReducer 库 。 不要犹豫,使用它。

提示4:拥有全局错误处理程序 (Tip 4: Have a global error handler)

It’s not necessary to keep an error for each entity. In most cases, we need to display an error dialog or something. The same error dialog for all them!

不必为每个实体都保留一个错误。 在大多数情况下,我们需要显示错误对话框或其他内容。 他们所有的错误对话框都一样!

Create a global error handler. In the most simple case it could look like this:

创建一个全局错误处理程序。 在最简单的情况下,它可能看起来像这样:

Then in your side-effect’s catch block dispatch ErrorInit. It could look like this with redux-thunk:

然后在副作用的catch块中调度ErrorInit 。 使用redux-thunk可能看起来像这样:

Then you could stop providing a reducer for error part of cats' state and CatsGetError just to flip loading flag.

然后,您可以停止为猫的状态和CatsGetError error部分提供化CatsGetError ,以翻转loading标志。

提示5:停止记忆所有内容 (Tip 5: Stop memoizing everything)

Let’s take a look at a mess we have with selectors one more time. I omitted makeSelectorCatsError because of what we discovered in the previous section.

让我们再来看一次与选择器的混乱情况。 由于我们在上一节中发现了什么,所以我省略了makeSelectorCatsError

Why would we create memoized selectors for everything? What’s there to memoize? Picking an object’s field by key (which is exactly what’s happening here) is O(1). Just write a regular non-memoized function. Use memoization only when you want to change the shape of the data in your store in a way that requires non-constant time before returning it to your component.

为什么我们要为所有内容创建记忆选择器? 有什么要记住的? 通过键选择对象的字段(这正是此处发生的情况)为O(1)。 只需编写一个常规的非记忆函数即可。 仅当您要更改存储中数据的形状而又需要非常长时间才能将其返回到组件之前,才使用备忘录。

Memoization could make sense only if computed some derived data. For this example let’s imagine that each cat is an object with field name and we need a string containing names of all cats.

只有计算了一些派生数据,记忆化才有意义。 对于此示例,我们假设每只猫都是一个具有字段name的对象,并且我们需要一个包含所有猫的名称的字符串。

结论 (Conclusion)

Let’s take a look at what we started with:

让我们看一下我们的开始:

And what the result is:

结果是:

Hopefully, you found something useful for your project. Feel free to communicate your feedback to me! I most certainly appreciate any criticism and questions.

希望您发现了一些对您的项目有用的东西。 随时向我传达您的反馈! 我当然很感谢任何批评和疑问。

翻译自: https://www.freecodecamp.org/news/yet-another-guide-to-reduce-boilerplate-in-your-redux-ngrx-app-3794a2dd7bf/

redux ngrx

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/392623.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode 242. 有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 示例 1: 输入: s “anagram”, t “nagaram” 输出: true 示例 2: 输入: s “rat”, t “car” 输出: false 代码 class Solution {public boolean isAnagram(String s, String t) {…

技巧:使用User Control做HTML生成

User Control大家肯定不会陌生,在使用ASP.NET的过程中,除了aspx页面,最常见的就莫过于ascx了。ascx是一个有独立逻辑的组件,提供了强大的复用特性,合理使用,能够大大提高开发效率。通过User Control直接生成…

Spring Boot干货系列:(二)配置文件解析

前言 上一篇介绍了Spring Boot的入门,知道了Spring Boot使用“习惯优于配置”(项目中存在大量的配置,此外还内置了一个习惯性的配置,让你无需手动进行配置)的理念让你的项目快速运行起来。所以,我们要想把S…

mysql常用操作记录

(1)判断表中一个字段是空,可为:字段名 IS NULL(2)类似oracle的decode作用:IF(字段名>0,字段名,0)(3)时间格式(年-月-日):DATE_FORM…

小爱音响调用php接口_阿里API调用二(PHP)

接口地址拼合成功后,用curl函数post获取阿里返回的完整数据,将地址传入getContent()方法中,绝对能获取用户数据。public function getContent($url){$ch curl_init();// 初始化curl_setopt($ch,CURLOPT_URL,$apiprourlall);curl_setopt($ch,…

leetcode 452. 用最少数量的箭引爆气球(贪心算法)

在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了。开始坐标总是小于结束坐标。 一支弓箭可以沿着 x…

javascript编程题_如何开始使用JavaScript进行竞争性编程

javascript编程题by Priyabrata Biswas通过Priyabrata Biswas 如何开始使用JavaScript进行竞争性编程 (How to get started with Competitive Programming in JavaScript) If you’re not familiar with competitive programming, basically it is a mind sport with the aim …

hibernate Criteria(条件查询接口)

Criteria&#xff08;条件查询接口&#xff09; // 1.简单查询 List<Customer> list session.createCriteria(Customer.class).list();// 2.条件查询: Criteria criteria session.createCriteria(Customer.class); criteria.add(Restrictions.eq("name",&quo…

ElastciSearch简单总结(笔记)

前言&#xff1a; 前段时间在项目中使用了es,作为一个当前比较流行的分布式搜索引擎&#xff0c;在学习和使用它的过程中&#xff0c;踩了不少坑&#xff0c;这篇文章先简单整理了一下&#xff0c;后续会整理一下之前踩过的一些坑。 1. ElastciSearch是什么 ElasticSearch是一…

记一次ArrayList产生的线上OOM问题

前言&#xff1a;本以为(OutOfMemoryError)OOM问题会离我们很远&#xff0c;但在一次生产上线灰度的过程中就出现了Java.Lang.OutOfMemoryError:Java heap space异常&#xff0c;通过对线上日志的查看&#xff0c;最终定位到ArrayList#addAll方法中&#xff0c;出现这个问题的原…

leetcode 222. 完全二叉树的节点个数(dfs)

给出一个完全二叉树&#xff0c;求出该树的节点个数。说明&#xff1a;完全二叉树的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中在该层最左边的若干位置。若最底…

css 计算属性的应用_如何使用一点CSS Grid魔术设计计算器应用

css 计算属性的应用by Deepika Gunda由Deepika Gunda 如何使用一点CSS Grid魔术设计计算器应用 (How to use a little CSS Grid magic to design a calculator app) This article is a quick intro to CSS Grid. We will be making a calculator using it.本文是CSS Grid的快速…

vc调试大全

一、调试基础 调试快捷键 F5&#xff1a; 开始调试 ShiftF5: 停止调试 F10&#xff1a; 调试到下一句&#xff0c;这里是单步跟踪 F11&#xff1a; 调试到下一句&#xff0c;跟进函数内部 ShiftF11: 从当前函数中跳出 CtrlF10: 调试到光标所在位置 F9&#xff1a; …

Google-Guava-EventBus源码解读

Guava是Google开源的一个Java基础类库&#xff0c;它在Google内部被广泛使用。Guava提供了很多功能模块比如&#xff1a;集合、并发库、缓存等&#xff0c;EventBus是其中的一个module&#xff0c;本篇结合EventBus源码来谈谈它的设计与实现。 概要 首先&#xff0c;我们先来预…

leetcode 1370. 上升下降字符串

给你一个字符串 s &#xff0c;请你根据下面的算法重新构造字符串&#xff1a; 从 s 中选出 最小 的字符&#xff0c;将它 接在 结果字符串的后面。 从 s 剩余字符中选出 最小 的字符&#xff0c;且该字符比上一个添加的字符大&#xff0c;将它 接在 结果字符串后面。 重复步骤…

mysql 设置事物自动提交_mysql事务自动提交的问题

1&#xff1a;mysql的aut0commit配置默认是开启的&#xff0c;也就是没执行一条sql都会提交一次&#xff0c;就算显示的开启事务也会导致多条SQL不在一个事务中&#xff0c;如果需要相关的SQL在同一个事务中执行&#xff0c;那么必须将autocommit设置为OFF&#xff0c;再显式开…

rest laravel_如何通过测试驱动开发来构建Laravel REST API

rest laravelby Kofo Okesola由Kofo Okesola 如何通过测试驱动开发来构建Laravel REST API (How to build a Laravel REST API with Test-Driven Development) There is a famous quote by James Grenning, one of the pioneers in TDD and Agile development methodologies:T…

python之numpy

numpy是一个多维的数组对象&#xff0c;类似python的列表&#xff0c;但是数组对象的每个元素之间由空格隔开。 一、数组的创建 1.通过numpy的array(参数)&#xff0c;参数可以是列表、元组、数组、生成器等 由arr2和arr3看出&#xff0c;对于多维数组来说&#xff0c;如果最里…

git 上传

转载于:https://www.cnblogs.com/benbentu/p/6543154.html

Liferay 部署war包时候的deployDirectory 细节分析

引入&#xff1a; 在上文中&#xff0c;我们从宏观上讲解了Liferay部署war包的动作是如何触发监听器并且完成部署过程的&#xff0c;但是其中最核心的一块deployDirectory我们没讲&#xff0c;它的作用是当有了临时目录并且已经把war包的内容展开到该目录之后&#xff0c;是如何…