props校验-基本使用
使用步骤
-
导入
prop-types
包 。这个包在脚手架创建项目时就自带了,无须额外安装import PropTypes from 'prop-types'
这里的PropTypes可以改成其他的名字. -
使用
组件名.propTypes = {属性名1: 类型1, ...}
来给组件的props添加校验规则,这里的propTypes是固定写法.
import PropTypes from 'prop-types'
class App extends React.component {
render(){
return (
<h1>Hi, {props.colors}</h1>
)
}
}
App.propTypes = {
// 约定colors属性为array类型
// 如果类型不对,则报出明确错误,便于分析错误原因
colors: PropTypes.array.isRequired
}
复制代码
常见规则
(1) 常见类型:array、bool、func、number、object、string
(2) React元素类型:element
(3) 必填项:isRequired
(4) 特定结构的对象:shape({ })
Com.propTypes = {
fn: PropTypes.func, // fn 是函数类型
isEdit: PropTypes.bool.isRequired // isEdit的类型是bool,且必须要传入
// 特定结构的对象
goodInfo: PropTypes.shape({ // goodInfo的格式一个对象,有 数值price属性 和 字符串name属性
price: PropTypes.number,
name: PropTypes.string
})
}
复制代码
props默认值
defaultProps
定义组件:
class App extends React.Component{
return (
<div>
此处展示props的默认值:{ this.props.pageSize }
</div>
)
}
// 设置默认值
App.defaultProps = {
pageSize: 10
}
// 类型限制
App.propTypes = {
pageSize: PropTypes.number
}
复制代码
使用组件:
// 不传入pageSize属性
<App />
复制代码
- 解构赋值的默认值
class App extends React.Component{
return (
// 解构赋值的默认值
const { pageSize = 10} = this.props
<div>
此处展示props的默认值:{ this.props.pageSize }
</div>
)
}
// 类型限制
App.propTypes = {
pageSize: PropTypes.number
}
复制代码
props校验和默认值简化-类的静态成员-static
什么是静态成员
- 静态成员:通过类或者构造函数本身才能访问的属性或者方法
- 实例成员: 通过实例调用的属性或者方法
class Person {
constructor(name){
this.name = name // 实例成员
}
// 方法1:在class内部 通过static来定义
static n = 1 // 静态成员 有static修饰
}
// 方法2 在class外部 通过类型.属性名来定义
Person.m = function() { console.log()}
复制代码
访问:
Person.n
Person.m()
复制代码
简化props校验和默认值
把校验规则和默认值放入class内部
组件生命周期
什么是生命周期
-
生命周期:一个事物从创建到最后消亡经历的整个过程
-
组件的生命周期:组件从被创建到挂载到页面中运行,再到组件不用时卸载的过程
什么是钩子函数
在生命周期的不同阶段,会自动被调用执行的函数,为开发人员在不同阶段操作组件提供了时机。
(注:只有类组件 才有生命周期钩子函数)
图片地址:projects.wojtekmaj.pl/react-lifec…
组件生命周期-挂载阶段
- 执行时机:组件创建时(页面加载时)
- 执行顺序:constructor() -> render() -> componentDidMount()
组件生命周期-更新阶段
- 执行顺序: render() -> componentDidUpdate()
如果有些事情是需要每次更新去做的,就可以写在componentDidUpdate中。例如:数据本地存储
三种操作可触发组件更新
- 调用setState。它能改数据&& 更新页面
- 调用forceUpdate()
- 组件接收到新的props
组件生命周期-卸载阶段
- 执行时机: 组件销毁
/* eslint-disable react/prop-types */
import React, { Component, createRef } from 'react'
import ReactDOM from 'react-dom'
class Son extends Component {
constructor () {
super()
this.timer = setInterval(() => {
console.log('子组件:', Date.now())
}, 1000)
this.fn = () => {
console.log('鼠标移动...')
}
window.addEventListener('mousemove', this.fn)
}
render () {
return <div>子组件:{this.props.content}</div>
}
componentDidUpdate () {
console.log('子组件: componentDidUpdate')
}
componentWillUnmount () {
console.log('子组件 卸载: componentWillUnmount')
// 删除事件
window.removeEventListener('mousemove', this.fn)
// 删除定时器
clearInterval(this.timer)
}
}
export default class App extends Component {
constructor () {
super()
console.log('1. constructor')
this.state = {
content: '',
isShow: true
}
this.refTxt = createRef()
}
hChange = (e) => {
this.setState({ content: e.target.value })
}
click = () => {
this.forceUpdate()
}
render () {
console.log('2. render')
return (
<div>
<button onClick={this.click}>更新</button>
组件<input value={this.state.content} onChange={this.hChange} />
<br />
{this.state.isShow && <Son content={this.state.content} />}
</div>
)
}
componentDidMount () {
console.log('3. componentDidMount')
console.log(this.refTxt.current)
// axios.get()
}
componentDidUpdate () {
console.log('更新完成: componentDidUpdate')
}
}
ReactDOM.render(<App />, document.getElementById('root'))
复制代码
setState进阶
setState的特点
- 可以表现为异步:setState调用之后,并不会立即去修改state的值,也不会立即去更新dom
- 多次调用会合并。setState({对象})会合并,再统一触发一次render()
- 使用不当会死循环。在componentDidUpdate, render 中调用setState()会导致死循环
import React, { Component } from 'react'
export default class App extends Component {
state = {
n: 1
}
hClick = () => {
this.setState({ n: 100 })
console.log(this.state.n)
console.log(document.getElementById('span').innerHTML) // 这会打印?1
}
render () {
return (
<div>
<button onClick={this.hClick}>click</button>
<span id="span">n: {this.state.n}</span>
</div>
)
}
}
复制代码
setState的第二个参数
(1) 格式一
this.setState({} [,回调函数])
回调函数是可选的,它的作用是:当本轮setState生效(state更新,页面ui更新)之后,会调用回调函数
import React, { Component } from 'react'
export default class App extends Component {
state = {
n: 1
}
hClick = () => {
this.setState({ n: this.state.n + 1 }, () => {
console.log(this.state.n) // 4
})
this.setState({ n: this.state.n + 2 }, () => {
console.log(this.state.n) // 4
})
this.setState({ n: this.state.n + 3 }, () => {
console.log(this.state.n) // 4
})
}
render () {
return (
<div>
<button onClick={this.hClick}>click</button>
<span id="span">n: {this.state.n}</span>
</div>
)
}
}
复制代码
(2) 格式二
this.setState((上一状态) => {
return 新状态
}[,回调函数])
复制代码
回调函数是可选的,它的作用是:当本轮setState生效(state更新,页面ui更新)之后,会调用回调函数
import React, { Component } from 'react'
export default class App extends Component {
state = {
n: 1
}
hClick = () => {
this.setState(
(preState) => ({ n: preState.n + 1 }),
() => {
console.log(this.state.n) // 7
}
)
this.setState(
(preState) => ({ n: preState.n + 2 }),
() => {
console.log(this.state.n) // 7
}
)
this.setState(
(preState) => ({ n: preState.n + 3 }),
() => {
console.log(this.state.n) // 7
}
)
}
render () {
return (
<div>
<button onClick={this.hClick}>click</button>
<span id="span">n: {this.state.n}</span>
</div>
)
}
}
复制代码
setState进阶-同步or异步
setState本身并不是一个异步(setTime, setInterval, ajax,Promise.then.....)方法,其之所以会表现出一种异步的形式,是因为react框架本身的性能优化机制.
(在React中,如果是由React引发的事件处理(比如通过onClick引发的事件处理),调用 setState 不会同步更新 this.state,除此之外的setState调用会同步执行this.state。所谓“除此之外”,指的是绕过React通过 addEventListener
直接添加的事件处理函数,还有通过setTimeout
|| setInterval
产生的异步调用。)
简而言之:
- 经过React 处理(事件回调,钩子函数)中的setState是
异步更新
- 没有经过React处理(通过
addEventListener
||setTimeout
/setInterval
)中的setState是同步更新
。
import reactDom from 'react-dom'
import React, { Component } from 'react'
class App extends Component {
state = {
n: 1
}
// setTimeout(() => {
// this.setState({ n: 2 })
// console.log(this.state.n)
// console.log(document.getElementById('btn').innerHTML)
// }, 2000)
componentDidMount () {
// this.setState({ n: 2 })
// console.log(this.state.n)
// console.log(document.getElementById('btn').innerHTML)
document.getElementById('btn').addEventListener('click', () => {
this.setState({ n: 2 })
console.log(this.state.n)
console.log(document.getElementById('btn').innerHTML)
})
}
click = () => {
this.setState({ n: 2 })
console.log(this.state.n)
console.log(document.getElementById('btn').innerHTML)
}
render () {
return (
<div>
{/* <button id="btn" onClick={this.click}> */}
<button id="btn" onClick={this.click}>
{this.state.n}
</button>
</div>
)
}
}
reactDom.render(<App />, document.getElementById('root'))
复制代码
参考链接 :