热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

React——Flow代码静态检查

为什么80%的码农都做不了架构师?FlowFlow是Facebook开源的静态代码检查工具,他的作用是在运行代码之前对React组件以及Jsx语法

为什么80%的码农都做不了架构师?>>>   hot3.png

Flow

Flow是Facebook开源的静态代码检查工具,他的作用是在运行代码之前对React组件以及Jsx语法进行静态代码的检查以发现一些可能存在的问题。Flow可以用于所有前端开发的项目而不仅仅局限于React,码友们可以到官网仔细了解(友情提示:可能需要VPN,非常不稳定),本文只介绍如何配合React开发使用。

Flow仅仅是一个用于检查的工具,安装使用都很方便,使用时注意以下3点即可:

  1. 将Flow增加到我们的项目中。
  2. 确保编译之后的代码移除了Flow相关的语法。
  3. 在需要检查的地方增加了Flow相关的类型注解。(类似与Java的Annotation机制)

接下来我们来一一说明以上三点的具体内容。码友们边阅读边操作即可。

将Flow增加到我们的项目中

安装最新版本的Flow:

Npm:

npm install --save-dev flow-bin

安装完成之后在package.json文件中增加执行脚本:

{// ..."scripts": {"your-script-name": "flow",// ...},// ...
}

然后初始化Flow:

npm run flow init

执行完成后,Flow会在终端输出一下内容:

> yourProjectName@1.0.0 flow /yourProjectPath
> flow "init"

然后在根目录下生成一个名为 .flowconfig 的文件,打开之后是这样的:

[ignore][include][libs][lints][options][strict]

基本上,配置文件没有什么特殊需求是不用去配置的,Flow默认涵盖了当前目录之后的所有文件。[include]用于引入项目之外的文件。例如:

[include]../otherProject/a.js[libs]

他会将和当前项目平级的otherProject/a.js 文件纳入进来。关于配置文件请看这里。

编译之后的代码移除Flow相关的语法

Flow在Javascript语法的基础上增加了一些 注解(annotation)进行了扩展。因此浏览器无法正确的解读这些Flow相关的语法,我们必须在编译之后的代码中(最终发布的代码)将增加的Flow注解移除掉。具体方法需要看我们使用了什么样的编译工具。下面将说明一些React开发常用的编译工具

Create React App

如果你的项目是使用Create React App直接创建的。那么移除Flow语法的事项就不用操心了,Create React App已经帮你搞定了这个事,直接跳过这一小节吧。

Babel

在15.x版本之前入坑React的码友应该绝大部分都用的Babel作为语法糖编译器,那个时候毕竟Create React App完全没有成熟。如果使用Babel我们还需要安装一个Babel对于Flow的preset:

npm install --save-dev babel-preset-flow

然后,我们需要在Babel的配置文件中添加一个Flow相关的preset:

{"presets": ["flow",//other config]
}

其他方式

如果你既没有使用Create React App也没使用Babel作为语法糖编译器,那么可以使用 flow-remove-types 这个工具在发布之前移除Flow代码。

运行Flow

完成上述步骤之后,就可以开始运行flow了:

npm run flow

然后会输类似一下的内容:

> yourProjectName@1.0.0 flow /yourProjectPath
> flowLaunching Flow server for /yourProjectPath
Spawned flow server (pid=10705)
Logs will go to /tmp/flow/zSworkzSchkuizSone-big-website.log
Monitor logs will go to /tmp/flow/zSworkzSchkuizSone-big-website.monitor_log
No errors!

第一次运行会生成很多临时文件比较慢,之后会快许多。

增加Flow注解

如果你了解C++/C#的元编程或者Java的Annotation,那么理解Flow的Annotation就会非常轻松。大概就是在文件、方法、代码块之前增加一个注解(Annotation)用来告知Flow的执行行为。

首先,Flow只检查包含 // @flow 注解的文件。所以如果需要检查,我们需要这样编写我们的文件:

// @flow
import React from 'react'class MyComponent extends React.Component {render(){return (

MyComponent
)}
}export default MyComponent

然后我们再运行Flow就变成这样的风格了:

> yourProjectName@1.0.0 flow /yourProjectPath
> flowError ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ dev/src/home/test.js:5:21Cannot use property Component [1] with less than 1 type argument.dev/src/home/test.js2│3│ import React from 'react'4│5│ class MyComponent extends React.Component {6│ render(){7│ return (

MyComponent
)8│ }/tmp/flow/flowlib_cc1898a/react.js[1] 26│ declare class React$Component {

到这里,Flow已经算是安装成功了,接写来的事是要增加各种注解以加强类型限定或者参数检测。之后的内容将简要介绍flow的相关语法规则。

React组件参数检查

https://www.chkui.com/article/react/react_typechecking_with_proptypes_and_dom_element介绍了React通过PropType机制限定使用者使用组件传递的参数类型以及范围,但是PropType是一种运行检测机制,在程序跑起来之后获取到具体数据才会执行检查。而Flow是静态检查,是在代码编译运行之前进行一次检查,两者相辅相成互不干扰。

Props参数检查

承接上面 MyComponent 的例子,我们引入Flow的注解对代码进行检查:

// @flow
// flow的例子,可以看看和PropType的差异在哪
import React from 'react'type Props = {num : number,text : ?string
}//通过<>引入Flow类型检查
//可以直接写成 React.Component<{num : number, text ?: string}>这样的形式
class MyComponent extends React.Component {render(){return (

{this.props.num}\{this.props.text}
)}
}export default MyComponent

然后在运行Flow&#xff0c;输出了No Error。

然后我们使用这个组件&#xff1a;

// &#64;flow
// flow的例子&#xff0c;可以看看和PropType的差异在哪
import React from &#39;react&#39;type Props &#61; {num : number,text : ?string
}class MyComponent extends React.Component {render(){this.props.myValue;return (

{this.props.num}\{this.props.text}
)}
}//void 表示 undefined 不传递参数
//这里传递类型发生错误
const UseComponent &#61; (props : void) &#61;>()export default UseComponent

运行flow之后输出&#xff1a;

Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ dev/src/home/test.js:12:20Cannot get this.props.myValue because property myValue is missing in Props [1].9│[1] 10│ class MyComponent extends React.Component {11│ render(){12│ this.props.myValue;13│ return (

{this.props.num}\{this.props.text}
)14│ }15│ }Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ dev/src/home/test.js:17:40Cannot create MyComponent element because:• string [1] is incompatible with number [2] in property num.• number [3] is incompatible with string [4] in property text.[2] 6│ num : number,[4] 7│ text : ?string:14│ }15│ }16│[1][3] 17│ const UseComponent &#61; (props : void) &#61;>()18│19│ export default UseComponentFound 3 errors

输出内容可以看出一共有2个错误栏输出&#xff1a;

  • 第一栏表示myValue并没有声明。
  • 第二栏[1]违反了[2]的限定&#xff0c;[3]违反了[4]的限定。我们将组件变更为即可检查通过。

增加对State的检查

React的数据通过两处控制——props 和 state。Flow也提供了state数据的检查&#xff0c;我们在例子中增加state检查&#xff1a;

// &#64;flow
// flow的例子&#xff0c;可以看看和PropType的差异在哪
import React from &#39;react&#39;type Props &#61; {num : number,text : ?string
}type State &#61; {count: number,
};class MyComponent extends React.Component {constructor(...props){super(...props)this.state &#61; {count:&#39;1&#39;}}render(){return (

{this.props.num}\{this.props.text}
)}
}const UseComponent &#61; (props : void) &#61;>()export default UseComponent

此时运行Flow会输出&#xff1a;

Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ dev/src/home/test.js:17:29Cannot assign object literal to this.state because string [1] is incompatible
with number [2] in property count.[2] 11│ count: number,12│ };13│14│ class MyComponent extends React.Component {15│ constructor(...props){16│ super(...props)[1] 17│ this.state &#61; {count:&#39;1&#39;}18│ }19│20│ render(){

检测出state.count在构造函数中赋值的类型错误。

组件默认值

使用Flow后一样可以使用默认值&#xff0c;但是必须要注意默认值的类型要和注解声明的一致&#xff1a;

import * as React from &#39;react&#39;;type Props &#61; {foo: number,
};class MyComponent extends React.Component {static defaultProps &#61; {foo: 42, };
}

函数类型的组件

除了使用Class关键字&#xff0c;使用函数同样可以构造一个React组件&#xff0c;配合Flow使用&#xff1a;

import React from &#39;react&#39;;type Props &#61; {//参数检查foo: number,bar?: string,
};function MyComponent(props: Props) {return

{props.bar}
;
}MyComponent.defaultProps &#61; {foo: 42 //指定默认值
};

React事件、子组件、高阶组件检查扩展

除了对单个组件基本的检查&#xff0c;Flow还提供了对React事件、refs、子组件、高阶组件、Redux。本文就不一一介绍了&#xff0c;有需要的码友可以按照下面的资源清单去了解相关的内容&#xff1a;

  • React事件
  • Refs引入对象
  • 子组件列表
  • 高阶组件参数
  • Redux整合

类型检查扩展

Flow会检查所有的Javascript基础类型——Boolean、String、Number、null、undefined&#xff08;在Flow中用void代替&#xff09;。除此之外还提供了一些操作符号&#xff0c;例如例子中的 text : ?string&#xff0c;他表示参数存在“没有值”的情况&#xff0c;除了传递string类型之外&#xff0c;还可以是null或undefined。需要特别注意的是&#xff0c;这里的没有值和Javascript的表达式的“非”是两个概念&#xff0c;Flow的“没有值”只有null、void&#xff08;undefined&#xff09;&#xff0c;而Javascript表达式的“非”包含&#xff1a;null、undefined、0、false。

除了前面的例子中给出的各种类型参数&#xff0c;Flow还有更丰富的检查功能&#xff0c;查看 这里 以了解更多内容。

React数据类型参考

对于Flow来说&#xff0c;除了常规的Javascript数据类型之外&#xff0c;React也有自己特有的数据类型。比如React.Node、React.Key、React.Ref<>等。需要详细了解的&#xff0c;可以查看官网关于React类型的说明。

需要特别说明的是&#xff0c;如果所要使用React的类型&#xff0c;在通过ES6引入React对象时需要使用这样的方式&#xff1a;

import * as React from &#39;react&#39;
//替换 import React from &#39;react&#39;//或者单独引入一个类型
//import type {Node} from &#39;react

两者的差异在于ES6的星号import的特性&#xff0c;使用*号会将一个文件中的所有 export 内容组合成一个对象返回&#xff0c;而不使用星号仅仅能获取到exprot default 那个原型。而引入Flow后不会修改React的默认导出类型&#xff0c;因为默认导出不一定是一个对象&#xff0c;他会通过export为React扩展更多的类型。

比如我们用React.Node限制render方法的返回类型&#xff1a;

import * as React from &#39;react&#39;
class MyComponent extends React.Component<{}> {render(): React.Node {// ...}
}

遇到的一些问题

我在使用的过程中目前遇到的问题之一是import 样式资源 或  图片时报 “./xxx.scss. Required module not found” 的以常&#xff0c;查看官方文档了解Flow只支持.js、.jsx、.mjs、.json的文件&#xff0c;如果需要导入其他文件需要并支持需要扩展options。在.flowconfig添加options&#xff1a;

[ignore]
[include]
[libs]
[lints]
[options]
module.file_ext&#61;.scss
[strict]

此外&#xff0c;某些IDE对Flow的支持不是很好。我目前所使用的webstorm 2017.3.5相对还不错&#xff0c;不过切记要到File->Setting->Languages&Frameworks->Javascript中将version设置为Flow。

写在最后的使用心得

引入并按照Flow的规范去约束每一个组件会导致开发量增加不少&#xff08;当然你引入不用是另外一回事&#xff0c;但是不用引入他做什么&#xff1f;&#xff09;。搭建好Flow的框架功能仅仅是开始&#xff0c;之后除了团队成员要去了解flow的使用方法&#xff0c;早期还会遇到各种坑需要去解决。而且Flow也要比React的 PropTypes 要”重“许多。

Javascript本来是一个类型推导的原型语言&#xff0c;弄个Flow进来搞得越来越像Java这种强类型语言&#xff0c;也不知道是好是坏&#xff0c;而Java10又学Javascript等加如了val这种类型推导得关键字....。

总的来说引入规范是有成本的&#xff0c;具体要看团队规模以及项目大小&#xff0c;不是引入越多得技术栈就越有逼格。如果你独立项目的前端开发人数并不多&#xff0c;或者代码膨胀&#xff08;代码腐烂&#xff09;速度也没有让你措手不及&#xff0c;建议慎重引入Flow。Flow除了开发人员自检还要整合到整个测试框架中&#xff0c;在集成测试或某个版本的代码发布之前进行集中检查。需要思考它在项目的开发、测试、仿真、上线迭代周期中扮演的角色&#xff0c;甚至整合到类似与CMMI之类的管理流程去反向量化考核代码质量。


转载于:https://my.oschina.net/chkui/blog/1807095


推荐阅读
  • React 小白初入门
    推荐学习:React官方文档:https:react.docschina.orgReact菜鸟教程:https:www.runoob.c ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • uniapp开发H5解决跨域问题的两种代理方法
    本文介绍了uniapp开发H5解决跨域问题的两种代理方法,分别是在manifest.json文件和vue.config.js文件中设置代理。通过设置代理根域名和配置路径别名,可以实现H5页面的跨域访问。同时还介绍了如何开启内网穿透,让外网的人可以访问到本地调试的H5页面。 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • OAuth2.0指南
    引言OAuth2.0是一种应用之间彼此访问数据的开源授权协议。比如,一个游戏应用可以访问Facebook的用户数据,或者一个基于地理的应用可以访问Foursquare的用户数据等。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 开发笔记:Python之路第一篇:初识Python
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Python之路第一篇:初识Python相关的知识,希望对你有一定的参考价值。Python简介& ... [详细]
  • Hadoop源码解析1Hadoop工程包架构解析
    1 Hadoop中各工程包依赖简述   Google的核心竞争技术是它的计算平台。Google的大牛们用了下面5篇文章,介绍了它们的计算设施。   GoogleCluster:ht ... [详细]
author-avatar
过客
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有