博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React Flow代码静态检查
阅读量:7257 次
发布时间:2019-06-29

本文共 8026 字,大约阅读时间需要 26 分钟。

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

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

Babel

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

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

然后,我们需要在添加一个Flow相关的preset:

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

其他方式

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

运行Flow

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

npm run flow

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

> yourProjectName@1.0.0 flow /yourProjectPath> flowLaunching Flow server for /yourProjectPathSpawned flow server (pid=10705)Logs will go to /tmp/flow/zSworkzSchkuizSone-big-website.logMonitor logs will go to /tmp/flow/zSworkzSchkuizSone-big-website.monitor_logNo errors!

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

增加Flow注解

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

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

// @flowimport 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.js      2│      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组件参数检查

介绍了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,输出了No Error。

然后我们使用这个组件:

// @flow// flow的例子,可以看看和PropType的差异在哪import React from 'react'type Props = {    num : number,    text : ?string}class MyComponent extends React.Component
{ render(){ this.props.myValue; return (
{
this.props.num}\{
this.props.text}
) }}//void 表示 undefined 不传递参数//这里传递类型发生错误const UseComponent = (props : void) =>(
)export default UseComponent

运行flow之后输出:

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 = (props : void) =>(
) 18│ 19│ export default UseComponentFound 3 errors

输出内容可以看出一共有2个错误栏输出:

  • 第一栏表示myValue并没有声明。
  • 第二栏[1]违反了[2]的限定,[3]违反了[4]的限定。我们将组件变更为<MyComponent num={2} text="2"/>即可检查通过。

增加对State的检查

React的数据通过两处控制—— 和 。Flow也提供了state数据的检查,我们在例子中增加state检查:

// @flow// flow的例子,可以看看和PropType的差异在哪import React from 'react'type Props = {    num : number,    text : ?string}type State = {    count: number,};class MyComponent extends React.Component
{ constructor(...props){ super(...props) this.state = {count:'1'} } render(){ return (
{
this.props.num}\{
this.props.text}
) }}const UseComponent = (props : void) =>(
)export default UseComponent

此时运行Flow会输出:

Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ dev/src/home/test.js:17:29Cannot assign object literal to this.state because string [1] is incompatiblewith 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 = {count:'1'} 18│ } 19│ 20│ render(){

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

组件默认值

使用Flow后一样可以使用默认值,但是必须要注意默认值的类型要和注解声明的一致:

import * as React from 'react';type Props = {  foo: number, };class MyComponent extends React.Component
{ static defaultProps = { foo: 42, };}

函数类型的组件

除了使用Class关键字,使用函数同样可以构造一个React组件,配合Flow使用:

import React from 'react';type Props = {
//参数检查 foo: number, bar?: string,};function MyComponent(props: Props) { return
{props.bar}
;}MyComponent.defaultProps = { foo: 42 //指定默认值};

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

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

类型检查扩展

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

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

React数据类型参考

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

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

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

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

比如我们用React.Node限制render方法的返回类型:

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

遇到的一些问题

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

[ignore][include][libs][lints][options]module.file_ext=.scss[strict]

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

写在最后的使用心得

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

JavaScript本来是一个类型推导的原型语言,弄个Flow进来搞得越来越像Java这种强类型语言,也不知道是好是坏,而Java10又学JavaScript等加入了val这种可以类型推导的关键字....。

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

转载地址:http://ipvdm.baihongyu.com/

你可能感兴趣的文章
Linux 任务控制(bg job fg nohup &)
查看>>
oracle 存储过程_oracle存储过程_oracle的存储
查看>>
alias用户个性化配置
查看>>
我的友情链接
查看>>
PIE SDK去相关拉伸
查看>>
最新云服务厂商产品列表---截至20141016
查看>>
今天开始学习
查看>>
MySQL数据库学习笔记(三)----基本的SQL语句
查看>>
Hadoop源代码分析(MapTask)
查看>>
SQL 2008新实例基础安装
查看>>
关于Google Sitelink
查看>>
zabbix企业应用之监控磁盘读写状态
查看>>
我的友情链接
查看>>
DOS命令行操作计划任务详解
查看>>
找出两个单链表里交叉的第一个元素
查看>>
Loop Guard - CCIE之Switching篇
查看>>
Android中使用javah生成jni头文件的正确方法
查看>>
svn 增加忽略和删除忽略文件
查看>>
JavaWeb获取请求参数的两种方式
查看>>
(九)2005年我的第一次软件行业创业,烧掉30万、2年时间打水漂的惨痛教训
查看>>