React 高级内容(1)

安装React开发调试工具(React Developer Tools)

安装步骤(需要科学上网):
安装步骤1
安装步骤2
安装步骤3

安装成功
在通过React开发并处于本地开发的页面上图标会显示为红色,说明安装成功:
React开发并处于本地开发的页面

通过React开发并处于线上版本的网页,图标会显示为黑色:
React开发并处于线上版本的页面

非React开发的页面上图标会显示为灰色:
非React开发的页面

React Developer Tools 的好处

  1. 方便进行 组件结构 的查询、
  2. 在组件传值调试时不需要反复通过 console.log 来打印信息,直接看 开发者工具 右侧 state 中是否有相关信息即可。

使用React Developer Tools

进入原始页面,打开 开发者工具 ,可以看到新增的 Component :
进入原始页面
在输入框内依次输入a b,可以看到右方 state 实时产生变化:
输入a b

可以很方便的进行 组件结构 查询:
组件查询


PropTypes与DefaultProps的应用

PropTypes 强校验

子组件在接受父组件传过来的值(即 属性 )时进行强校验。他可以要求父组件给子组件传的值是什么类型的。如若不是也并不会报错,只会在 开发者工具 中给出警告。

使用步骤

  1. 脚手架工具中已经有 prop-types 的包,所以我们可以直接在 子组件 中顶部引入 PropTypes
    1
    import PropTypes from 'prop-types';
  2. 子组件 export default 顶上使用 propTypes (注意是小写)限制父组件传过来的值的类型(更多值的类型可以看下面”PropTypes不同的验证函数“):
    1
    2
    3
    4
    5
    6
    7
    // 使用propTypes限制父组件传过来的值的类型
    TodoItem.propTypes = {
    // 注意PropTypes大小写,上面必须小写,下面是import中自定义的名字
    content: PropTypes.string,
    deleteItem: PropTypes.func,
    index: PropTypes.number
    }
  3. 如果将 index 的 PropTypes要求 改为 string ,则一旦提交输入内容后就会给出 警告 ,告诉我们子组件接收 index 时希望得到的是 string 类型的而不是 number :
    警告

isRequired强制传值

总结

  1. 当父组件没有向子组件传某个值时,某个值对应的propTypes是不生效的。
  2. 使用isRequired可以强制要求父组件向子组件传递某个值,如果父组件并未传值就会报出 警告 。

例子1
子组件上增加 test (实际上父组件并未传 test ):
子组件上增加test
对子组件上 test 进行强校验:
子组件上强校验
然而到页面上输入时并未报出警告,也就是说test: PropTypes.string是没有生效的。

例子2
在 propTypes 中使用isRequired强制要求父组件向子组件传递test值:
添加isRequired
父组件并未传值,报出 警告:
警告


DefaultProps 设置默认值

当父组件没有向子组件传递某个值,而子组件使用了该值时,可以在子组件中设置DefaultProps来规定该值的默认值。

注意:上面强校验时引入了PropTypes是因为需要使用PropTypes内的类型(string、func、number等),而DefaultProps不需要另外引入别的包。

有时候你使用isRequired强制要求父组件传过来的值实际上没办法传,这时候就需要用到默认值来解决报错问题,结合上面的例子,我们在子组件中给test一个默认值
子组件中
结果


官网深入学习

  1. 打开英文官网https://reactjs.org/。(中文官网较为滞后,推荐英文官网)
  2. Docs(文档)=> ADVANCED GUIDES(高级指南)=> typechecking-with-proptypes

PropTypes

  1. 直接拉到中间看 PropTypes使用方法的 demo
    demo
  2. 再往下看可以看到 PropTypes 可以使用的各种值
    PropTypes 的各种值
  3. 还可以 使用instanceOf来判断接收的值是不是Message的一个实例 等,PropTypes可以做非常丰富的代码检测:
    接4的图片
  4. 假设我们希望例子中的content可以是number或者string类型,我们可以使用文档中给出的**oneOfType来完成“或者”的语法**:
    1
    2
    3
    4
    5
    // content 可以是number或者string类型
    content: PropTypes.oneOfType([
    PropTypes.number,
    PropTypes.string
    ]),

PropTypes不同的验证函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import PropTypes from 'prop-types';

MyComponent.propTypes = {
// 你可以声明一个道具是一个特定的JS类型。默认情况下,这些都是可选的。
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,

// 任何可以渲染的东西:数字,字符串,元素或数组(或片段)。
optionalNode: PropTypes.node,

// React元素
optionalElement: PropTypes.element,

// 一个React元素类型(即MyComponent)。
optionalElementType: PropTypes.elementType,

// 你也可以声明prop是某个类的实例。 内部使用的是JS的instanceof运算符。
//使用instanceOf来判断接收的值是不是Message的一个实例
optionalMessage: PropTypes.instanceOf(Message),

// 你可以通过将它作为枚举来确保你的prop值仅限于特定的值。
optionalEnum: PropTypes.oneOf(['News', 'Photos']),

// 可以是许多类型之一的对象
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),

// 某种特定类型的数组(数组元素为number的数组)
optionalArrayOf: React.PropTypes.arrayOf(PropTypes.number),

// 具有某种特定类型的属性值的对象
optionalObjectOf: PropTypes.objectOf(PropTypes.number),

// 采取特定样式的对象
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),

// 你可以用`isRequired`来连接到上面的任何一个类型,以确保如果没有提供该props的话会显示一个警告。
requiredFunc: PropTypes.func.isRequired,

// 任何数据类型
requiredAny: PropTypes.any.isRequired,

// 您还可以指定自定义验证器。如果验证失败,它应该返回一个Error对象。 不要`console.warn`或`throw`,因为这在`oneOfType`中不起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},

// 您还可以为`arrayOf`和`objectOf`提供自定义类型检查器。 如果检查失败,它应该返回一个Error对象。
// 检查器将为数组或对象中的每个键调用验证函数。
// 检查器有两个参数,第一个参数是数组或对象本身,第二个是当前项的键。
customArrayProp: React.PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
};

defaultProps

defaultProps 使用方法的 demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}

// 指定name的默认值:Stranger
Greeting.defaultProps = {
name: 'Stranger'
};

// 显示 “你好,陌生人”:
ReactDOM.render(
<Greeting />,
document.getElementById('example')
);

props,state与render函数的关系

之所以state中的数据一变页面就会自动发生变化是因为页面是通过render函数渲染出来的,而每当组件的state或者props发生改变时,render函数就会重新执行
(props发生改变,归根到底还是父组件的state发生了变化,所以我们也可以理解为state或者props发生改变时父子组件的render函数都会重新执行)
当父组件的render函数被运行时,它的子组件的render都将被重新运行一次。

state与render函数的关系
每当组件的state内数据发生改变时,render函数就会重新执行。可以看TodoList.js来帮助理解。

props与render函数的关系
每当组件的props内的数据发生改变时,render函数就会重新执行。
总结:当父组件的render函数被运行时,它的子组件的render都将被重新运行一次。

例子

  1. 在父组件中引入子组件Test:
    import Test from "./Test"
  2. 在父组件中将子组件Test放在无序列表下方位置并将state中的inputValue传过去,**每当父组件的render函数被运行时就会打印”render”**:
    父组件中
  3. 新建一个子组件Test.js,**每当子组件的render函数被运行时就会打印”Test render”**并在页面上显示父组件传过来的content(即state中的inputValue值):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import React, { Component } from 'react'//imrc

    class Test extends Component {
    render() {
    console.log("Test render");
    return (
    <div>{this.props.content}</div>
    )
    }
    }

    export default Test;

结果
输入1

解释

  1. 最初的时候父组件需要渲染,子组件也需要渲染,所以 开发者工具 中显示了“render”和“Test render”。
  2. 输入1后,inputValue发生改变,父组件的state发生改变,所以父组件render函数重新运行,多打出来一行“render”。
  3. 输入1后**inputValue一变content就会变(因为父组件传值<Test content={this.state.inputValue} />),content一变props就变了(因为子组件中<div>{this.props.content}</div>),props发生改变时,render函数就会重新执行,所以显示“Test render”**。

,