七、setState同步异步
import React, { Component } from 'react'
export default class App extends Component {
state = {
a: 1
}
render() {
return (
<div>
{this.state.a}
<button onClick={this.Add1}>加一</button>
<button onClick={this.Add2}>加一</button>
</div>
)
}
Add1 = () => {
this.setState({
a: this.state.a + 1
})
console.log(this.state.a);
this.setState({
a: this.state.a + 1
})
console.log(this.state.a);
}
Add2 = () => {
setTimeout(() => {
this.setState({
a: this.state.a + 1
})
console.log(this.state.a);
this.setState({
a: this.state.a + 1
})
console.log(this.state.a);
}, 0);
}
}
首先,我们在这里打印发现setState在处在同步逻辑中,会发生异步更新状态,更新真实的DOM;处在异步的逻辑中,同步的更新状态,同步更新真实的DOM。(这里需要注意,在React18之前是这样的,18版本之后就发生了改变是wu’lun同步的还是异步的,都会异步的更新状态和DOM)
import React, { Component } from 'react'
export default class App extends Component {
state = {
a: 1
}
render() {
return (
<div>
{this.state.a}
<button onClick={this.Add1}>加一</button>
<button onClick={this.Add2}>加一</button>
</div>
)
}
Add1 = () => {
this.setState({
a: this.state.a + 1
}, () => {
console.log(this.state.a);
})
console.log(this.state.a);
}
Add2 = () => {
setTimeout(() => {
this.setState({
a: this.state.a + 1
}, () => {
console.log(this.state.a);
})
console.log(this.state.a);
}, 0);
}
}
所以,我们就必须都在setState接收第二个参数,第二个参数是回调函数,状态和DOM更新完后就会被调用。
八、属性props
props 是正常是外部传入的,组件内部也可以通过一些方式来初始化的设置,属性不能被组件自己更 改,但是你可以通过父组件主动重新渲染的方式来传入新的 props。
states状态只能内部自己使用,外面无法改变。
属性是描述性质、特点的,组件自己不能随意更改。
总的来说,在使用一个组件的时候,可以把参数放在标签的 属性当中,所有的属性都会作为组件 props 对象的键值。通过箭头函数创建的组件,需要通过函数的 参数来接收 props:
(1) 在组件上通过key=value 写属性,通过this.props获取属性,这样组件的可复用性提高了。
(2) 注意在传参数时候,如果写成isShow=“true” 那么这是一个字符串 如果写成isShow={true} 这个是布尔值。
(3) {…对象} 展开赋值
子组件Navbar.js:
import React, { Component } from 'react'
// 这里prop-types是react内置提供给我们验证的模块,直接import就可以
// 命名随便即可
import PropTyp from 'prop-types'
console.log(PropTyp);
export default class Navbar extends Component {
// 属性校验的另一种写法
static propTypes = {
title: PropTyp.string,
isshow: PropTyp.bool,
}
static defaultProps = {
title: "",
isshow: true,
flag: false
}
render() {
// 属性通过父组件传过来,this.props
let { title, isshow, flag } = this.props
return (
<div>
{/* 条件渲染 */}
{isshow && <button>返回按钮</button>}
{title}
{flag && <button>首页按钮</button>}
</div>
)
}
}
// // 类属性 这是一种写法
// Navbar.propTypes = {
// title: PropTyp.string,
// isshow: PropTyp.bool,
// }
// 默认属性
// Navbar.defaultProps = {
// title: "",
// isshow: true,
// flag: false
// }
父组件:
import React, { Component } from 'react'
import Navbar from './Navbar'
export default class App extends Component {
state = {
flag: true,
proplist: {
title: "demo",
isshow: true
}
}
render() {
return (
<div>
<div>
<h2>首页</h2>
<Navbar title="首页" isshow={true} flag={this.state.flag}></Navbar>
</div>
<div>
<h2>列表</h2>
<Navbar title="列表" isshow={false}></Navbar>
</div>
<div>
<h2>购物车</h2>
<Navbar title="购物车" isshow={false}></Navbar>
</div>
<div>----------------------------------</div>
<Navbar {...this.state.proplist}></Navbar>
</div>
)
}
}
九、属性和状态对比
相似点:都是纯js对象,都会触发render更新,都具有确定性(状态/属性相同,结果相同)
不同点:
- 属性能从父组件获取,状态不能
- 属性可以由父组件修改,状态不能
- 属性能在内部设置默认值,状态也可以,设置方式不一样
- 属性不在组件内部修改,状态要在组件内部修改
- 属性能设置子组件初始值,状态不可以
- 属性可以修改子组件的值,状态不可以
state的主要作用是用于组件保存、控制、修改自己的可变状态。 state在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为state是一个局部的、只能被组件自身控制的数据源。 state中状态可以通过this.setState方法进行更新, setState 会导致组件的重新渲染。
props的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的 props ,否则组件的 props 永远保持不变。
没有state的组件叫无状态组件(stateless component),设置了state的叫做有状态组件 (stateful component)。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。
补充:
函数式组件时props属性接收(通过函数中参数获取)
import React from 'react'
export default function SideBar(props) {
return (
<div>sideBar</div>
)
}