我们来了到了一个非常尴尬的章节,很多初学的朋友可能对这一章的知识点不屑一顾,觉得用不用对程序功能也没什么影响。但其实这一章节的知识在你构建多人协作、大型的应用程序的时候也是非常重要的,不可忽视。

都说 JavaScript 是一门灵活的语言 —— 这就是像是说“你是个好人”一样,凡事都有背后没有说出来的话。JavaScript 的灵活性体现在弱类型、高阶函数等语言特性上。而语言的弱类型一般来说确实让我们写代码很爽,但是也很容易出 bug。

变量没有固定类型可以随意赋值,在我们构建大型应用程序的时候并不是什么好的事情。你写下了 let a = {} ,如果这是个共享的状态并且在某个地方把 a = 3,那么 a.xxx 就会让程序崩溃了。而这种非常隐晦但是低级的错误在强类型的语言例如 C/C++、Java 中是不可能发生的,这些代码连编译都不可能通过,也别妄图运行。

大型应用程序的构建其实更适合用强类型的语言来构建,它有更多的规则,可以帮助我们在编写代码阶段、编译阶段规避掉很多问题,让我们的应用程序更加的安全。JavaScript 早就脱离了玩具语言的领域并且投入到大型的应用程序的生产活动中,因为它的弱类型,常常意味着不是很安全。所以近年来出现了类似 TypeScript 和 Flow 等技术,来弥补 JavaScript 这方面的缺陷。

React.js 的组件其实是为了构建大型应用程序而生。但是因为 JavaScript 这样的特性,你在编写了一个组件以后,根本不知道别人会怎么使用你的组件,往里传什么乱七八糟的参数,例如评论组件:

class Comment extends Component {
const { comment } = this.props
render () {
return (
<div className='comment'>
<div className='comment-user'>
<span>{comment.username} </span>:
</div>
<p>{comment.content}</p>
</div>
)
}
}

但是别人往里面传一个数字你拿他一点办法都没有:

<Comment comment={1} />

JavaScript 在这种情况下是不会报任何错误的,但是页面就是显示不正常,然后我们踏上了漫漫 debug 的路程。这里的例子还是过于简单,容易 debug,但是对于比较复杂的成因和情况是比较难处理的。

于是 React.js 就提供了一种机制,让你可以给组件的配置参数加上类型验证,就用上述的评论组件例子,你可以配置 Comment 只能接受对象类型的 comment 参数,你传个数字进来组件就强制报错。我们这里先安装一个 React 提供的第三方库 prop-types

npm install --save prop-types

它可以帮助我们验证 props 的参数类型,例如:

import React, { Component } from 'react'
import PropTypes from 'prop-types' class Comment extends Component {
static propTypes = {
comment: PropTypes.object
} render () {
const { comment } = this.props
return (
<div className='comment'>
<div className='comment-user'>
<span>{comment.username} </span>:
</div>
<p>{comment.content}</p>
</div>
)
}
}

注意我们在文件头部引入了 PropTypes,并且给 Comment 组件类添加了类属性 propTypes,里面的内容的意思就是你传入的 comment 类型必须为 object(对象)。

这时候如果再往里面传入数字,浏览器就会报错:

出错信息明确告诉我们:你给 Comment 组件传了一个数字类型的 comment,而它应该是 object。你就清晰知道问题出在哪里了。

虽然 propTypes 帮我们指定了参数类型,但是并没有说这个参数一定要传入,事实上,这些参数默认都是可选的。可选参数我们可以通过配置 defaultProps,让它在不传入的时候有默认值。但是我们这里并没有配置 defaultProps,所以如果直接用 <Comment /> 而不传入任何参数的话,comment 就会是 undefinedcomment.username 会导致程序报错:

这个出错信息并不够友好。我们可以通过 isRequired 关键字来强制组件某个参数必须传入:

...
static propTypes = {
comment: PropTypes.object.isRequired
}
...

那么会获得一个更加友好的出错信息,查错会更方便:

React.js 提供的 PropTypes 提供了一系列的数据类型可以用来配置组件的参数:

PropTypes.array
PropTypes.bool
PropTypes.func
PropTypes.number
PropTypes.object
PropTypes.string
PropTypes.node
PropTypes.element
...

更多类型及其用法可以参看官方文档: Typechecking With PropTypes - React

组件参数验证在构建大型的组件库的时候相当有用,可以帮助我们迅速定位这种类型错误,让我们组件开发更加规范。另外也起到了一个说明文档的作用,如果大家都约定都写 propTypes ,那你在使用别人写的组件的时候,只要看到组件的 propTypes就清晰地知道这个组件到底能够接受什么参数,什么参数是可选的,什么参数是必选的。

总结

通过 PropTypes 给组件的参数做类型限制,可以在帮助我们迅速定位错误,这在构建大型应用程序的时候特别有用;另外,给组件加上 propTypes,也让组件的开发、使用更加规范清晰。

这里建议大家写组件的时候尽量都写 propTypes,有时候有点麻烦,但是是值得的。


因为第三方评论工具有问题,对本章节有任何疑问的朋友可以移步到 React.js 小书的论坛 发帖,我会回答大家的疑问。

React.js 小书 Lesson24 - PropTypes 和组件参数验证的更多相关文章

  1. 【React.js小书】动手实现 React-redux(五):Provider - 方志

    我们要把 context 相关的代码从所有业务组件中清除出去,现在的代码里面还有一个地方是被污染的.那就是 src/index.js 里面的 Index: 1234567891011121314151 ...

  2. React.js 小书 Lesson22 - props.children 和容器类组件

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson22 转载请注明出处,保留原文链接和作者信息. 有一类组件,充当了容器的作用,它定义了一种外层 ...

  3. React.js 小书 Lesson20 - 更新阶段的组件生命周期

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson20 转载请注明出处,保留原文链接和作者信息. 从之前的章节我们了解到,组件的挂载指的是将组件 ...

  4. React.js 小书 Lesson19 - 挂载阶段的组件生命周期(二)

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson19 转载请注明出处,保留原文链接和作者信息. 这一节我们来讨论一下对于一个组件来说,cons ...

  5. React.js 小书 Lesson18 - 挂载阶段的组件生命周期(一)

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson18 转载请注明出处,保留原文链接和作者信息. 我们在讲解 JSX 的章节中提到,下面的代码: ...

  6. React.js 小书 Lesson8 - 组件的组合、嵌套和组件树

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson8 转载请注明出处,保留原文链接和作者信息. 继续拓展前面的例子,现在我们已经有了 Heade ...

  7. React.js 小书 Lesson7 - 组件的 render 方法

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson7 转载请注明出处,保留原文链接和作者信息. React.js 中一切皆组件,用 React. ...

  8. React.js 小书介绍

    React.js 小书 Github 关于作者 这是一本关于 React.js 的小书. 因为工作中一直在使用 React.js,也一直以来想总结一下自己关于 React.js 的一些知识.经验.于是 ...

  9. React.js小书总结

    (迁移自旧博客2017 08 27) 第一阶段 react的组件相当于MVC里面的View. react.js 将帮助我们将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合.嵌套,就成 ...

随机推荐

  1. Public Bike Management (30)(DFS,VRCTOR,模拟)(PAT甲级)

    #include<bits/stdc++.h>using namespace std;const int inf = 1e9;int sum,n,tar,m;int num[507];in ...

  2. PHP 执行系统外部命令的方法 system() exec()

    PHP作为一种服务器端的脚本语言,像编写简单.或者是复杂的动态网页这样的任务,它完全能够胜任.但事情不总是如此,有时为了实现某个功能,必须借助于操作系统的外部程序(或者称之为命令),这样可以做到事半功 ...

  3. Mysql创建、删除用户[转]

    MySql中添加用户,新建数据库,用户授权,删除用户,修改密码(注意每行后边都跟个;表示一个命令语句结束): 1.新建用户 登录MYSQL: @>mysql -u root -p @>密码 ...

  4. [转] iOS中@class #import #include 简介

    [转载自:http://blog.csdn.net/chengwuli125/article/details/9705315] 一.解析        很多刚开始学习iOS开发的同学可能在看别人的代码 ...

  5. 方法引用(Method reference)和invokedynamic指令详细分析

    方法引用(Method reference)和invokedynamic指令详细分析 invokedynamic是jvm指令集里面最复杂的一条.本文将详细分析invokedynamic指令是如何实现方 ...

  6. openstack的部署与运维

    来公司几个月了,除了搭建了kvm虚拟机,使用3台虚拟机组合成一个openstack的网络环境.还没有正式将openstack搭建起来过.时间都在开发web程序.不过openstack也是要学习的.只能 ...

  7. js 时间戳的转化,js 日期转成标准字符串,日期格式的相互转化

    1.时间的获取 var myDate = new Date(); myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取完整的年份(4位,1 ...

  8. oracle nvl()函数

    oracle的nvl()函数作用是当第一个值不为null时,返回第一个值,否则返回第二个值. 当第一个值为一个运算表达式时,那么第二个的值被限定为只能是NUMBER类型或者能隐式转换为NUMBER类型 ...

  9. CAS总结

    n++的问题不能保证原子操作. 因为被编译后拆分成了3个指令,先获取值,然后加一,然后写回内存.把变量声明为volatile,volatile只能保证内存可见性,但是不能保证原子性,在多线程并发下,无 ...

  10. acl权限使用

    1.acl的设置技巧 *setfacl 用法: setfactl [-bkRd] [{-m|-x} acl参数] 目标文件名 -m:设置后续的acl参数给文件使用,不可与-x合用 -x:删除后续的ac ...