当前位置: 首页 > 编程日记 > 正文

使用Flow检查React,Redux和React-Redux的全面指南

by Fabian Terh

由Fabian Terh

使用Flow检查React,Redux和React-Redux的全面指南 (A comprehensive guide to type checking React, Redux, and React-Redux with Flow)

This article is divided into 4 sections:

本文分为4个部分:

  1. Type checking Redux actions, action creators, and reducers

    类型检查Redux操作,操作创建者和简化器
  2. Installing Flow library definitions

    安装流库定义
  3. Type checking application state

    类型检查应用程序状态
  4. Type checking Redux store and dispatch

    类型检查Redux存储和调度

While there are a bunch of guides on the first section which are immensely helpful, I found only a paucity of articles on 3 and 4. After a long session of Google searches, diving into source code, and trial and error, I decided to put together what I’ve learned and write this tutorial as a one-stop guide to type checking your React + Redux + React-Redux application with Flow.

尽管在第一部分中有很多指南对您有很大帮助,但是我发现关于3和4的文章很少。经过一番Google搜索,深入研究源代码以及反复试验之后,我决定放下结合我所学到的知识,并将本教程作为一站式指南来编写,以使用Flow对您的React + Redux + React-Redux应用程序进行类型检查。

1.类型检查Redux操作,操作创建者和简化器 (1. Type checking Redux actions, action creators, and reducers)

动作 (Actions)

Redux actions are essentially vanilla Javascript objects with a mandatory type property:

Redux操作本质上是具有强制type属性的原始Javascript对象:

// This is an action{  type: 'INCREASE_COUNTER',  increment: 1}

Following best practices, you may want to define and use action type constants instead. If so, the above snippet would probably look something like this:

按照最佳实践,您可能想要定义和使用操作类型常量 。 如果是这样,上面的代码段可能看起来像这样:

const INCREASE_COUNTER = 'INCREASE_COUNTER';
// This is an action{  type: INCREASE_COUNTER,  increment: 1}

Type checking is easy (we’re dealing with regular JavaScript here):

类型检查很容易(我们在这里处理常规JavaScript):

type $action = {  type: 'INCREASE_COUNTER',  increment: number};

Note that you cannot substitute the literal string type with the constant INCREASE_COUNTER. This is a limitation of Flow itself.

注意,不能用常量INCREASE_COUNTER代替文字字符串类型 。 这是Flow本身的局限性 。

动作创作者 (Action creators)

Since action creators are just functions that return actions, we’re still dealing with regular Javascript. This is how a type checked action creator can look like:

由于动作创建者只是返回动作的函数,因此我们仍在处理常规Javascript。 这是类型检查动作创建者的样子:

function increaseCounter(by: number): $action {  return {    type: INCREASE_COUNTER, // it's okay to use the constant here    increment: by  };}

减速器 (Reducers)

Reducers are functions that handle actions. They receive a state and an action, and return the new state. At this juncture, it’s important to think about how your state will look like (state shape). In this very simple example, the state shape comprises of only a single key counter which takes on a number type value:

减速器是处理动作的功能。 他们收到一个状态和一个动作,并返回新状态。 在此关头,考虑一下您的状态(状态形状)是很重要的。 在这个非常简单的示例中,状态形状仅包含一个带有number类型值的键counter

// State shape{  counter: <number>}

And so your reducer could look like this:

因此,您的减速器可能如下所示:

const initialState = { counter: 0 };
function counter(state = initialState, action) {  switch (action.type) {    case INCREASE_COUNTER:      return Object.assign({}, state, {        counter: action.increment + state.counter      });        default:      return state;  }};

Note: In this particular example, Object.assign({}, state, { ... }) is redundant because the store consists only of 1 key/value pair. I could just as easily return the last argument to the function. However, I included the full implementation for correctness.

注意:在此特定示例中, Object.assign({}, state, { ... }) 是多余的,因为存储仅由1个键/值对组成。 我可以轻松地将最后一个参数返回给函数。 但是,为了正确起见,我包含了完整的实现。

Typing the state and reducer is simple enough. Here is the typed version of the above snippet:

输入状态和reducer很简单。 这是类型 以上代码段的版本:

type $state = {  +counter: number};
const initialState: $state = { counter: 0 };
function counter(  state: $state = initialState,  action: $action): $state {    switch (action.type) {    case INCREASE_COUNTER:      return Object.assign({}, state, {        counter: action.increment + state.counter      });        default:      return state;  }};

安装流库定义 (Installing Flow library definitions)

Flow library definitions (or libdefs) provide type definitions for third-party modules. In this case, we are using React, Redux, and React-Redux. Instead of typing these modules and their functions manually, you can install their type definitions using flow-typed:

流库定义 (或libdefs)为第三方模块提供类型定义。 在这种情况下,我们使用React,Redux和React-Redux。 您可以使用flow-typed安装它们的类型定义,而不必手动键入这些模块及其功能:

npm install -g flow-typed
// Automatically download and install all relevant libdefsflow-typed install
// Orflow-typed install <package>@<version> // e.g. redux@4.0.0

Library definitions are installed to the flow-typed folder, which lets Flow work out of the box without any further configuration (details).

库定义将安装到flow-typed文件夹中,这使Flow可以直接使用,而无需任何进一步的配置( 详细信息 )。

类型检查应用程序状态 (Type checking application state)

Previously, we have already typed the state like this:

以前,我们已经输入了如下状态:

type $state = {  +counter: number};

While this works for a simple example like the one above, it breaks down once your state becomes significantly larger. You would have to manually edit type $state every time you introduce a new reducer or modify an existing one. You also wouldn’t want to keep all your reducers in the same file. What you want to do instead is to refactor your reducers into separate modules, and use Redux’s combineReducers function.

尽管这对于上面的示例很简单,但是一旦您的状态显着变大,它就会崩溃。 每次引入新的reducer或修改现有的reducer时,都必须手动编辑type $state 。 您也不想将所有的reducer放在同一文件中。 相反,您要做的是将减速器重构为单独的模块,并使用Redux的combineReducers函数。

Since the focus of this article is on type checking a React/Redux/React-Redux application, and not on building one, I’m going to assume you are familiar with the combineReducers function. If not, head over to Redux’s tutorial to learn all about it.

由于本文的重点是对React / Redux / React-Redux应用程序进行类型检查 ,而不是构建应用程序,因此,我假定您熟悉combineReducers函数。 如果没有,请转到Redux的教程以了解所有内容。

Suppose we introduce a new action/reducer pair in a separate module:

假设我们在单独的模块中引入了一个新的动作/减速器对:

// playSong.js
export const PLAY_SONG = 'PLAY_SONG';
// Typing the actionexport type $playSongAction = {  type: 'PLAY_SONG',  song: ?string};
// Typing the action creatorexport function playSong(song: ?string): $playSongAction {  return {    type: PLAY_SONG,    song: song  };};
// Typing arg1 and the return value of the reducer [*1]export type $song = ?string;
// Typing the state [*1]export type $songState = {  +song: $song};
// [*1][*2]const initialValue: $song = null;
// Typing the reducer [*1][*3]function song(  state: $song = initialValue,  action: $playSongAction): $song {    switch (action.type) {    case PLAY_SONG:      return action.song;        default:      return state;  }};

[*1]: If we’re using the combineReducers function, it’s important to note that your reducer should no longer be returning the state, but rather the value to the key in the state. In this regard, I think Redux’s tutorial is a bit lacking in clarity, as it does not state this explicitly, although it is clear from the example code snippets.

[* 1]:如果我们使用combineReducers函数,则需要注意的是, reduce不再应该返回状态,而应返回state中 。 在这方面,我认为Redux的教程有点不够清晰,因为虽然从示例代码片段中可以清楚地看到,但它没有明确说明。

[*2]: Reducers are not allowed to return undefined, so we have to settle for null.

[* 2]:减速器不允许返回undefined ,因此我们必须满足null

[*3]: Since the reducer is no longer receiving and returning a state in the form of { song: string }, but rather the value to the song key in the state object, we need to change the types of its first argument and return value from $songState to $song.

[* 3]:由于reducer不再以{ song: string }的形式接收和返回状态,而是状态对象中song键的 ,因此我们需要更改其第一个参数的类型,并从$songState$song返回值。

We modify and refactor increaseCounter as well:

我们修改和重构increaseCounter还有:

// increaseCounter.js
export const INCREASE_COUNTER = 'INCREASE_COUNTER';
export type $increaseCounterAction = {  type: 'INCREASE_COUNTER',  increment: number};
export function increaseCounter(by: number): $action {  return {    type: INCREASE_COUNTER,    increment: by  };};
export type $counter = number;
export type $counterState = {  +counter: $counter};
const initialValue: $counter = 0;
function counter(  state: $counter = initialValue,  action: $increaseCounterAction): $counter {    switch (action.type) {    case INCREASE_COUNTER:      return action.increment + state;        default:      return state;  }};

Now we have 2 action/reducer pairs.

现在我们有2个动作/减速器对。

We can create a new State type to store the type of our application state:

我们可以创建一个新的State类型来存储我们的应用程序状态的类型:

export type State = $songState & $counterState;

This is a Flow intersection type, and is equivalent to:

这是流交叉点类型 ,等效于:

export type State = {  song: $song,  counter: $counter};

If you don’t want to create $songState and $counterState only for use in intersection-typing the application state State, that’s perfectly fine too — go with the second implementation.

如果您不想创建$songState$counterState仅用于交叉键入应用程序状态State ,那也很好-与第二个实现一起进行。

类型检查Redux存储和调度 (Type checking Redux store and dispatch)

I found that Flow was reporting errors in my containers (in the context of the container/component paradigm).

我发现Flow正在报告我的容器中的错误(在容器/组件范例的上下文中)。

Could not decide which case to select. Since case 3 [1] may work but if it doesn't case 6 [2] looks promising too. To fix add a type annotation to dispatch [3].

This was with regard to my mapDispatchToProps function. Cases 3 and 6 are as follows:

这与我的mapDispatchToProps函数有关。 情况3和6如下:

// flow-typed/npm/react-redux_v5.x.x.js
// Case 3declare export function connect<  Com: ComponentType<*>,  A,  S: Object,  DP: Object,  SP: Object,  RSP: Object,  RDP: Object,  CP: $Diff<$Diff<ElementConfig<Com>;, RSP>, RDP>  >(  mapStateToProps: MapStateToProps<S, SP, RSP>,  mapDispatchToProps: MapDispatchToProps<A, DP, RDP>): (component: Com) => ComponentType<CP & SP & DP>;
// Case 6declare export function connect<  Com: ComponentType<*>,  S: Object,  SP: Object,  RSP: Object,  MDP: Object,  CP: $Diff<ElementConfig<Com>, RSP>  >(  mapStateToProps: MapStateToProps<S, SP, RSP>,  mapDispatchToPRops: MDP): (component: Com) => ComponentType<$Diff<CP, MDP> & SP>;

I don’t know why this error occurs. But as the error hints, typing dispatch fixes it. And if we’re typing dispatch, we might as well type store too.

我不知道为什么会发生此错误。 但是如错误提示所示,键入dispatch解决该问题。 而且,如果我们输入dispatch ,我们也可以输入store

I couldn’t find much documentation on this aspect of typing a Redux/React-Redux application. I learned by diving into the libdefs and looking at the source code for other projects (albeit a demonstration project). If you have any insights, please let me know so I can update this post (with proper attribution, of course).

在键入Redux / React-Redux应用程序的这一方面,我找不到很多文档。 我通过深入libdefs并查看其他项目 (尽管是演示项目)的源代码来学习 。 如果您有任何见解,请告诉我,以便我可以更新此帖子(当然,请注明出处)。

In the meantime, I’ve found that this works:

同时,我发现这可行:

import type {  Store as ReduxStore,  Dispatch as ReduxDispatch} from 'redux';
// import any other variables and types you may need,// depending on how you organized your file structure.
// Reproduced from earlier onexport type State = {  song: $song,  counter: $counter};
export type Action =   | $playSongAction  | $increaseCounterAction
export type Store = ReduxStore<State, Action>;
export type Dispatch = ReduxDispatch<Action>;

Heading into your container modules, you can then proceed to type mapDispatchToProps as follows: const mapDispatchToProps = (dispatch: Dispatch) => { ... };

进入容器模块,然后可以按如下所示继续输入mapDispatchToPropsconst mapDispatchToProps = (dispatch: Dispatch) => { ... };

结语 (Wrapping up)

This has been a pretty long post, and I hope you found it useful. I wrote it partly because of a dearth of resources regarding the later sections of this article (and partly to organize my thoughts and consolidate what I’ve learned).

这是一篇很长的文章,希望您觉得它有用。 我写这篇文章的部分原因是由于本文后面各部分的资源匮乏(部分原因是为了整理我的思想并巩固我所学的知识)。

I can’t guarantee that the guidance in this article follows best practices, or is conceptually sound, or even 100% correct. If you spot any errors or issues, please let me know!

我不能保证本文中的指导遵循最佳实践,或者从概念上讲是正确的,甚至100%正确。 如果您发现任何错误或问题,请告诉我!

翻译自: https://www.freecodecamp.org/news/a-comprehensive-guide-to-type-checking-react-redux-and-react-redux-with-flow-4219bdc4ef89/

相关文章:

微信小程序WebSocket实现聊天对话功能完整源码

相关文章&#xff1a; 1.小程序聊天群&#xff0c;发送语音&#xff0c;文字&#xff0c;图片。 2.微信小程序集成腾讯IM&#xff0c;实现实时音视频通话&#xff0c;1V1聊天 3.云开发微信小程序聊天群 4.接入网易云信IM即时通讯的微信小程序聊天室 5.微信小程序聊天功能 …

codevs 1203 判断浮点数是否相等

1203 判断浮点数是否相等 时间限制: 1 s空间限制: 128000 KB题目等级 : 青铜 Bronze题目描述 Description给出两个浮点数&#xff0c;请你判断这两个浮点数是否相等输入描述 Input Description输入仅一行&#xff0c;包含两个浮点数输出描述 Output Description输出仅一行&…

通过代码自定义cell(cell的高度不一致)

我们知道&#xff0c;在iOS中&#xff0c;自定义cell的方式有两种&#xff1a; 一是通过xib创建 .二是通过代码自定义cell 这里我说下通过代码自定义的cell。 当我们的应用显示的cell比较复杂&#xff0c;显示的行高都不一样&#xff0c;比如新浪微博 这时用系统自带的cell…

通过构建城市来解释HTML,CSS和JavaScript之间的关系

by Kevin Kononenko凯文科诺年科(Kevin Kononenko) 通过构建城市来解释HTML&#xff0c;CSS和JavaScript之间的关系 (The relationship between HTML, CSS and JavaScript explained by building a city) If you have ever visited a walkable city like New York, then you c…

url参数解析 url解析 ?解析成对象

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 代码&#xff1a; // url参数解析 function getUrlkey(url) {var params {};var urls url.split("?");if (urls[1]) {var arr urls[1].split("&");for …

【bzoj1070】[SCOI2007]修车 最小费用流

原文地址&#xff1a;http://www.cnblogs.com/GXZlegend/p/6798411.html 题目描述 同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员&#xff0c;不同的技术人员对不同的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序…

“Assign Random Colors” is not working in 3ds Max 2015

Go to Customize -> Preferences…-> General (tab) Uncheck “Default to By Layer for New Nodes”转载于:https://www.cnblogs.com/cindy-hu-23/p/4476293.html

计算机编程课程顺序_您可以在6月开始参加630项免费的在线编程和计算机科学课程...

计算机编程课程顺序Six years ago, universities like MIT and Stanford first opened up free online courses to the public. Today, more than 800 schools around the world have created thousands of free online courses.六年前&#xff0c;麻省理工学院和斯坦福大学等大…

卡片右上角三角形效果,按钮点击变色

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 效果图&#xff1a; 实现代码&#xff1a; <view classprivilege_list><view classprivilege_card {{in_right_top1?"bg":""}} bindtapin_card id1&g…

数据挖掘基本任务

数据挖掘基本任务 数据挖掘主要做什么&#xff1f;换而言之&#xff0c;数据挖掘主要解决什么问题呢&#xff1f;这些问题&#xff0c;可以归结为数据挖掘的基本任务。 数据挖掘的基本任务包括分类与预测、聚类分析、关联规则、奇异值检测和智能推荐等。通过完成这些任务&#…

41-First Missing Positive

【题目】 Given an unsorted integer array, find the first missing positive integer. For example,Given [1,2,0] return 3,and [3,4,-1,1] return 2. Your algorithm should run in O(n) time and uses constant space. 【analyze】 1.由于是无序的&#xff0c;所以处理起来…

javascript迭代器_JavaScript符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释...

javascript迭代器by rajaraodv通过rajaraodv JavaScript符号&#xff0c;迭代器&#xff0c;生成器&#xff0c;异步/等待和异步迭代器-全部简单解释 (JavaScript Symbols, Iterators, Generators, Async/Await, and Async Iterators — All Explained Simply) Some JavaScrip…

jquery总结和注意事项

1、关于页面元素的引用通过jquery的$()引用元素包括通过id、class、元素名以及元素的层级关系及dom或者xpath条件等方法&#xff0c;且返回的对象为jquery对象&#xff08;集合对象&#xff09;&#xff0c;不能直接调用dom定义的方法。 2、jQuery对象与dom对象的转换只有jquer…

第4次作业类测试代码+043+杨晨宇

triangle的代码&#xff1a; package triangle;import java.text.DecimalFormat;public class Triangle {public Triangle() {}/** 判断三角形的类型*/public String triangleshape(int a, int b, int c) {if ((a < 1 || a > 100) || (b < 1 || b > 100) || (c <…

微信小程序让屏幕自动向下滚动

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; wx.pageScrollTo(OBJECT) 基础库 1.4.0 开始支持&#xff0c;低版本需做兼容处理 将页面滚动到目标位置。 OBJECT参数说明&#xff1a; 参数名类型必填说明scrollTopNumber是滚动到…

这就是为什么我们需要在React的类组件中绑定事件处理程序

by Saurabh Misra索拉米斯拉(Saurabh Misra) 这就是为什么我们需要在React的类组件中绑定事件处理程序 (This is why we need to bind event handlers in Class Components in React) While working on React, you must have come across controlled components and event han…

深入JDK源码,这里总有你不知道的知识点!

Java的基础知识有很多&#xff0c;但是我认为最基础的知识应该要属jdk的基础代码&#xff0c;jdk的基础代码里面&#xff0c;有分了很多基础模块&#xff0c;其中又属jdk包下面的lang包最为基础。 我们下面将总结和分析一下lang包下面最为基础和常用的几个部分。 1:常用的对象类…

JS同时上传表单图片和表单信息并把上传信息存入数据库,带php后端源码

微信小程序开发交流qq群 581478349 承接微信小程序开发。扫码加微信。 利用JQ&#xff0c;jquery.form.js&#xff0c;bootstrap实现上传表单图片和表单信息并把上传的图片地址&#xff0c;input填写的信息存入数据库&#xff0c;上传的图片存入服务器。 效果 前端&#xff…

java 的回调函数

在Java中&#xff0c;通常就是编写另外一个类或类库的人&#xff08;李四&#xff09;规定一个接口&#xff0c;然后你&#xff08;张三&#xff09;来实现这个接口&#xff0c;然后把这个实现类的一个对象作为参数传给别人的程序&#xff0c;别人的程序必要时就会通过那个接口…

无导师学习_如何找到一位导师并加快学习速度:新手指南。

无导师学习by Victor Cassone由Victor Cassone 如何找到一位导师并加快学习速度&#xff1a;新手指南。 (How to find a mentor and accelerate your learning: a beginner’s guide.) One of my biggest regrets while learning to program was that I isolated myself too m…

wamp环境下安装imagick扩展

先上图&#xff0c;如下是安装成功后的phpinfo()界面: 安装步骤&#xff1a; 1、先确定安装版本&#xff0c;比如我的的php &#xff1a; php7.0.12 x86 ts 那么就需要三方版本 要一致&#xff1a;imagick软件本身( 如x86 )、php本身( x86 ts (thread safe) )、php扩展php_ima…

php批量修改文件名

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 代码 <?php header("Content-type: text/html; charsetutf-8"); //利用PHP目录和文件函数遍历用户给出目录的所有的文件和文件夹&#xff0c;修改文件名称 function f…

领域驱动设计 敏捷_反馈失败:发现敏捷数据驱动的致命弱点的风险

领域驱动设计 敏捷by Phil Seaton菲尔西顿(Phil Seaton) 反馈失败&#xff1a;发现敏捷数据驱动的致命弱点的风险 (Feedback fail: discover the risk of Agile’s data-driven Achilles heel) 您是否有遭受数据驱动欺骗的危险&#xff1f; (Are you in danger of data-driven…

微信小程序 点击卡片切换 动画效果

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; html <view classaa><image animation"{{animationData0}}" classimg0 stylez-index: {{index_0}}; bindtapbindtap_img id0 src"{{clubs[0].image}}"&…

Log4J的配置

Log4J简介日志记录功能是一个项目中重要的组成部分&#xff0c;Log4J是APache下的一个开源日志组件&#xff0c;为java开发者提供了很大的便利。 Loggers,日志信息的优先级日志信息的优先级从高到低有ERROR、WARN、 INFO、DEBUG&#xff0c;分别用来指定这条日志信息的重要程度…

Xcode中的NSLog详解

探究原因基本上这种事情一定可以在Apple文档中找到&#xff0c;看NSLog的文档&#xff0c;第一句话就说&#xff1a;Logs an error message to the Apple System Log facility.&#xff0c;所以首先&#xff0c;NSLog就不是设计作为普通的debug log的&#xff0c;而是error log…

java web程序示例_想要建立一些有趣的东西吗? 这是示例Web应用程序创意的列表。...

java web程序示例Interested in learning JavaScript? Get my ebook at jshandbook.com有兴趣学习JavaScript吗&#xff1f; 在jshandbook.com上获取我的电子书 If you’re reading this post, you are probably looking for an idea. You likely want to build a simple app …

python读取文件

请参考&#xff1a;http://www.cnblogs.com/sysuoyj/archive/2012/03/14/2395789.html转载于:https://www.cnblogs.com/yajing-zh/p/6807971.html

[Git/Github] ubuntu 14.0 下github 配置

转载自&#xff1a;http://www.faceye.net/search/77573.html 一&#xff1a;创建Repositories1:首先在github下创建一个帐号。这个不用多说&#xff0c;然后创建一个Repositories。2:然后在ubuntu下安装git相关的东东&#xff1a; 1sudo apt-get install git-core git-gui git…

php ile_get_contents无法请求https连接的解决方法

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 1.windows下的PHP&#xff0c;只需要到php.ini中把extensionphp_openssl.dll前面的;删掉&#xff0c;重启服务就可以了。