0%

React入门2

条件渲染

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
import React from "react"
export default class IfDemo extends React.Component{
/**
* 常见的场景:
* 1、对视图条件进行切换
* 2、做缺省值
*/
constructor(){
super()
this.state = {
isLogin:false,
names:["czk"]

}
}
clickHandler = ()=>{
this.setState(
{
isLogin:this.state.isLogin = true
}
)
}
render(){
const { names } = this.state;
let showView = this.state.isLogin ?
<div>登录成功</div>:
<div>请登录</div>
return(
<div>
条件渲染:{showView}
<button onClick={this.clickHandler}>登录</button>
{
names.length>0?
<div>
{
names.map((element, index)=>{
return <h1 key={index}>{element}</h1>
})
}
</div>:<div>请等待数据正在请求。。。</div>
}

</div>
)
}
}

列表渲染&Key

  • 在需要循环某字段创建标签时,可以使用map函数来创建,在循环时记住要把key属性加上去,因为在多次渲染的过程中,如果元素没有被改变(是依靠index来确定元素有没有改变),它是不会被重新渲染的,这可以提高渲染性能。如果不加key属性,则每次渲染都会全部重新渲染
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
import React from "react"
export default class KeyDemo extends React.Component{
constructor(){
super();
this.state = {
userinfo:[
{
name:"Axl",
age:18,
sex:"男",
hobbies:["打乒乓", "打篮球"]
},
{
name:"Czk",
age:18,
sex:"男",
hobbies:["打乒乓", "打篮球"]
}
]
}
}
clickHandler = ()=>{
this.setState(
{
userinfo:this.state.userinfo.concat([{
name:"Sash",
age:18,
sex:"女",
hobbies:[
"打乒乓", "打篮球"
]
}])
}
)
}
render(){
return (
<div>
<p>列表渲染</p>
<div>
<ul>
{
this.state.userinfo.map((element, index)=>{
return (
<li key={index}>
<span>{element.name}</span>
<span>{element.age}</span>
<span>{element.sex}</span>
<div>
{
element.hobbies.map((element, index)=>{
return <span key={index}>{element}</span>
})
}
</div>
</li>
)
})
}
</ul>
</div>
<button onClick={this.clickHandler}>添加数据</button>
</div>
)
}
}

RefsAndDOM

  • 受控组件,就是渲染的控件属性用的是state中的值
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
import React from "react"
//受控组件
//可以看到使用了state保存属性的值,在需要修改值的时候,需要使用setState函数来进行修改,这种方法修改值比较复杂,若控件不多的话,建议使用这种方法
export default class FormDemo extends React.Component{
constructor(){
super();
this.state = {
value:""
}
}
handleSubmit = (e)=>{

console.log(this.state.value)
e.preventDefault();
}
changeHandler = (e)=>{
this.setState(
{value:this.state.value = e.target.value}
)
}
render(){
return(
<div>
<form onSubmit={this.handleSubmit}>
<input type="text" value={this.state.value} onChange={this.changeHandler}/>
<input type="submit" value="提交"/>
</form>
</div>
)
}
}
  • 非受控组件,就是控件的渲染使用了ref属性来渲染
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React from "react"

//非受控组件
//这种方法改变值比较简单,不用写触发事件的函数
//在引用使用了ref属性的控件时,this.user.current就等价于<input type="text" ref={this.username}/>
export default class RefsForm extends React.Component{
constructor(){
super();
//创建一个ref
this.username = React.createRef();
}
handleSubmit = (e)=>{
e.preventDefault();
console.log(this.username.current.value)
}
render(){
return (
<form onSubmit = {this.handleSubmit}>
<input type="text" ref={this.username}/>
<input type="submit" value="提交"/>
</form>
)
}
}

状态提升

  • 在 React 中,将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,便可实现共享 state。这就是所谓的“状态提升”
  • 首先,写一个判断水是否煮开了的组件
1
2
3
4
5
6
7
import React from "react"
export default function BoilingVerdict(props) {
if(props.celsius >= 100){
return <p>The water would boil.</p>;
}
return <p>The water would not boil.</p>;
}
  • 创建temperatureInput组件,用来封装输入
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
import React from "react"

const scaleNames = {
c: 'Celsius',
f: 'Fahrenheit'
}
export default class TemperatureInput extends React.Component{
constructor(props){
super(props)
this.handleChange = this.handleChange.bind(this);
this.state = {
temperature : ''
}
}
handleChange(e){
this.props.onTemperatureChange(e.target.value)
}
render(){
const temperature = this.props.temperature;
const scale = this.props.scale;
return(
<fieldset>
<legend>Enter temperature in {scaleNames[scale]}:</legend>
<input value={temperature} onChange = {this.handleChange}></input>

</fieldset>
)
}
}
  • 再创建父组件Calculator,用来转换华/摄氏度
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
import React from "react"
import BoilingVerdict from "./boilingVerdict"
import TemperatureInput from "./temperatureInput";
export default class Calculator extends React.Component{
constructor(props){
super(props);
this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
this.state = {
scale:'c', temperature : ''
}


}
handleCelsiusChange(temperature) {
this.setState({
scale: 'c',
temperature:temperature
});
}

handleFahrenheitChange(temperature) {
this.setState({
scale: 'f',
emperature:temperature
});
}
render(){
const temperature = this.state.temperature;
const scale = this.state.scale;
const celsius = (scale === 'f' ? tryConvert(temperature, toCelsius) : temperature);
const fahrenheit = (scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature);
return (
<div>
<TemperatureInput
scale="c"
temperature={celsius}
onTemperatureChange={this.handleCelsiusChange} />
<TemperatureInput
scale="f"
temperature={fahrenheit}
onTemperatureChange={this.handleFahrenheitChange} />
<BoilingVerdict
celsius={parseFloat(celsius)} />
</div>
)
}
}
function toCelsius(fahrenheit) {
return (fahrenheit - 32) * 5 / 9;
}

function toFahrenheit(celsius) {
return (celsius * 9 / 5) + 32;
}

function tryConvert(temperature, convert) {
const input = parseFloat(temperature);
if (Number.isNaN(input)) {
return '';
}
const output = convert(input);
const rounded = Math.round(output * 1000) / 1000;
return rounded.toString();
}
  • 整个状态提升的过程是这样的:
    1. 在摄氏度输入框输入,触发handleChange函数,利用了props触发父组件中子组件的onTemperatureChange属性
    2. 调用了handleCelsiusChange,把父组件中的state对象重新赋值
    3. 此时父组件的渲染函数被重新调用,温度互相转换
    4. 最后通过props把转换后的温度传递到子组件中。
    5. 华氏度和摄氏度一样

组合组件&继承

  • 在父组件中若子组件的内部包含了其他标签,则子组件可以使用this.props.children去引用它,比如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React from "react"
export default class Compose extends React.Component{
render(){
return (
<div>
Compose:
{/* 这里的children就是Compose中的div */}
{this.props.children}
</div>
)
}
}
//父组件
<Compose>
<div>
我是组合效果
</div>
</Compose>

类型验证

  • 类型验证是React中子组件对组件传递过来的props对象中的数据进行验证

  • 使用PropTypes进行类型验证:

  • 先在子组件中引入PropTypes(import PropTypes from “prop-types”)

  • 然后在子组件中创建类型验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from "react"
import PropTypes from "prop-types"
export default class PropsTypeValidation extends React.Component{
render(){
return (
<div>
Hello:{this.props.title}
</div>
)
}
}
//表示title为string类型,且为必需
PropsTypeValidation.propType = {
title:PropTypes.string.isRequired
}
//为title设置默认值
PropsTypeValidation.defaultProps = {
title:"默认标题"
}
  • 还有很多的验证方法
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
76
77
78
79
80
81
82
83
84
85
86
MyComponent.propTypes = {
// 你可以将属性声明为 JS 原生类型,默认情况下
// 这些属性都是可选的。
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,

// 任何可被渲染的元素(包括数字、字符串、元素或数组)
// (或 Fragment) 也包含这些类型。
optionalNode: PropTypes.node,

// 一个 React 元素。
optionalElement: PropTypes.element,

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

// 你也可以声明 prop 为类的实例,这里使用
// JS 的 instanceof 操作符。
optionalMessage: PropTypes.instanceOf(Message),

// 你可以让你的 prop 只能是特定的值,指定它为
// 枚举类型。
optionalEnum: PropTypes.oneOf(['News', 'Photos']),

// 一个对象可以是几种类型中的任意一个类型
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),

// 可以指定一个数组由某一类型的元素组成
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),

// 可以指定一个对象由某一类型的值组成
optionalObjectOf: PropTypes.objectOf(PropTypes.number),

// 可以指定一个对象由特定的类型值组成
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),

// An object with warnings on extra properties
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),

// 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保
// 这个 prop 没有被提供时,会打印警告信息。
requiredFunc: PropTypes.func.isRequired,

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

// 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
// 请不要使用 `console.warn` 或抛出异常,因为这在 `onOfType` 中不会起作用。
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: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
};
-------------本文结束感谢您的阅读-------------