类组件
类组件的定义有如下要求:
组件的名称必须要大写字符开头;
类组件需要继承React.Component;
类组件必须实现render函数。
import React, {Component} from 'react'
export default class App extends Component {
constructor() {
super()
this.state = {
msg: 'Hello State'
}
}
render() {
return (
<div>{this.state.msg}</div>
)
}
}
函数组件
函数组件的特点:
没有this对象;
没有内部状态(state);
没有生命周期。
import React from 'react'
export default function App() {
return (
<div>Hello World</div>
)
}
生命周期
从创建到销毁的整个过程被称之为“生命周期”。
生命周期的各个阶段:
装载阶段(Mount),组件第一次在DOM树中被渲染的过程;
更新过程(Update),组件状态发生变化,重新更新渲染的过程;
卸载过程(Unmount),组件从DOM树中被移除的过程。
我们谈React生命周期时,主要谈的类的生命周期,因为函数式组件是没有生命周期函数的,但我们可以通过hooks来模拟一些生命周期的回调。
常用生命周期函数需要处理的部分事务:
Constructer:
通常给this.state赋值对象来初始化内部的state;
为事件绑定实例(this)。
componentDidMount:
依赖于DOM的操作可以在这里进行;
在此发送网络请求;
可以在此添加一些订阅。
componentDidUpdate:
当组件更新后,可以在此对DOM进行操作;
可以对更新前后的props进行比较,也可以进行网络请求。
componentWillUnmount:
- 在此方法中执行必要的清除操作(例:清除定时器、取消网络请求);
认识组件的嵌套
App组件是Header、Main、Footer组件的父组件;
Main组件是Banner、ProductList组件的父组件。
组件间的通信
父传子
父组件在展示子组件,可能会传递一些数据给子组件:
父组件通过 属性=值 的形式来传递给子组件数据;
子组件通过 props 参数获取父组件传递过来的数据。
- 类组件父传子:
// Father
import React, { Component } from 'react'
import ChildCpn from './component/ChildCpn'
export default class App extends Component {
render() {
return (
<div>
<ChildCpn name='Sytus' age='17' height='1.7'></ChildCpn>
<ChildCpn name='Ming' age='40' height='1.8'></ChildCpn>
</div>
)
}
}
// Child
import React, { Component } from 'react'
export default class ChildCpn extends Component {
constructor(props) {
super(props)
}
render() {
const { name, age, height } = this.props
return (
<div>
<h2>子组件展示数据: {name + ' ' + age + ' ' + height}</h2>
</div>
);
}
}
- 函数组件父传子:
//Child
import React from 'react'
export function ChildCpn(props) {
const { name, age, height } = props
return (
<div>
<h2>子组件展示数据: {name + ' ' + age + ' ' + height}</h2>
</div>
);
}
子传父
父组件给子组件传递一个回调函数,在子组件中调用这个函数即可。
希望在子函数中实现对父函数内值的影响,需要在父函数中定义方法传递到子函数中实现。
//Father
export default class App extends Component {
constructor() {
super()
this.state = {
count: 0,
}
}
render() {
return (
<div>
<h2>当前计数:{this.state.count}</h2>
<CounterBtn plus={e => this.plus()}></CounterBtn>
</div>
)
}
plus() {
this.setState({
count: this.state.count + 1
})
}
}
//Child
class CounterBtn extends Component {
constructor(props) {
super(props)
}
render() {
const { plus } = this.props;
return (
<button onClick={plus}>+</button>
)
}
}
跨组件通信
Context的应用
当前Context已经进行了更新,需要查阅最新文档。
属性验证
对于传递给子组件的数据,有时我们可能希望进行验证。
- 导入prop-types:
import PropTypes from 'prop-types'
- 在接收数据的组件中设置验证:
import PropTypes from 'prop-types'
export default class ChildCpn extends Component {
....
}
ChildCpn.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
height: PropTypes.number
}
组件优化
shouldComponentUpdate
只能在类组件中进行使用,对render函数的调用进行优化,是一个生命周期函数。
shouldComponentupdate(nextProps, nextState) {
// nextProps是最新的Props
// nextState是最新的State
return boolean // true or false, 决定是否执行render()
}
PureComponent
如果类组件继承PureComponent,则会在组件内部自动实现shouldComponentUpdate。
import React, {PureComponent} from 'react'
class App extends PureConponent {
......
}
memo
memo是一个高阶组件,决定函数组件是否重新渲染,可以优化组件性能。
import React, {memo} from 'react'
const MemoApp = memo(function App() {
......
})
export default MemoApp
Portals
某些情况下,我们希望渲染的内容独立于父组件,甚至是独立于当前挂载到的 DOM 元素中(默认都是挂载到 id 为 root 的 DOM 元素上的)。
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀方案。
第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串,或 fragment;
第二个参数(container)是一个 DOM 元素。
React.createPortal(child, container)
以下进行实例:
- 首先在 index.html 中写入一个新的节点:
<body>
<div id="root"></div>
<div id="model"></div>
</body>
- 再在父组件中传入需要渲染的元素:
export default class Portals extends PureComponent {
render() {
return (
<div>
<h2>Portals</h2>
<Model>
<h2>Model</h2>
</Model>
</div>
)
}
}
- 最后创建一个新的组件,并在内部引入 ReactDOM 后进行操作:
import React, { PureComponent } from 'react'
import ReactDOM from 'react-dom'
class Model extends PureComponent {
render() {
return (
ReactDOM.createPortal(
this.props.children, // 获取所有需要渲染的元素
document.querySelector('#model') // 挂载到节点上
)
)
}
}
Fragment
通常我们要求一个组件中返回内容时包裹一个 DIV 元素:
return (
<div></div>
)
如果我们不希望渲染这个 DIV 元素,那我们就可以使用 Fragment。
import React, {Fragment} from 'react'
return (
<Fragment></Fragment>
)
React 提供了 Fragment 的短语法:
<> </>
但如果需要在 Fragment 中添加 key,则不能使用短语法。
StrictMode
<React.StrictMode>
<App/> // App组件及子组件开启了严格模式
</React.StrictMode>
StrictMode 是一个用来突出显示应用程序中潜在问题的工具:
StrictMode本身不会渲染任何可见的UI;
它为其后代元素触发额外的检查和警告;
严格模式检查仅在开发模式下运行,它们不会影响生产构建。
检查内容:
识别不安全的生命周期;
识别过时的 ref API;
检查意外的副作用:
组建的 constructor() 会被调用两次;
这是严格模式下故意的操作,方便程序员查看逻辑代码在调用多次下是否会产生副作用;
在生产环境中,是不会被调用两次的;
使用废弃的findDOMNode方法;
检测过时的 context API。