React性能优化
React更新流程
:::info
- 同层节点之间相互比较,不会跨节点比较
- 不同类型的节点,产生不同的树结构
- 可以通过key来指定哪些节点在不同的渲染下保持稳定
- key应该是唯一的
- key不要使用随机数
-
shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState)
if(this.state.message !== nextState.message) {
return true
}
return false
}
返回值为true, 则需要调用render方法
- 返回值为false, 不调用render方法
- 默认返回true, 也就是只要state发生改变,就会调用render方法
PureComponent
:::info 调用!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)进行浅层比较 ::: ```javascript import React, { PureComponent } from ‘react’ class App extends PureComponent {
}
<a name="zCynZ"></a>
#### 高阶组件memo
函数式组件在props没有改变时,也是不希望重新渲染其DOM树结构,可是使用`**memo**`来包裹该组件
```javascript
import { memo } from 'react'
const Profile = memo(function(props) {
return <h2>{props.message}</h2>
})
export default Profile
数据不可变的力量
shouldComponentUpdate(nextProps,nextState) {
if(nextState !== this.state) {
return true
}
return false
}
// 新开辟一个books堆内存
const books = [...this.state.books]
books.push(newBook)
this.setState({books})
// 仍然为原来的堆内存
this.state.books.push(newBook)
Ref的使用
获取ref
某些情况下,我们需要获取DOM,可以通过refs
进行操作
<h2 ref="str">Hello</h2>
// 通过this.refs.str获取DOM元素
通过**this.ref.current**
获取DOM实例或者类组件实例
import React, { createRef } from 'react'
this.titleRef = createRef()
<h2 ref={this.titleRef}></h2>
// 通过this.titleRef.current获取DOM
constructor() {
this.titleRef = null
}
<h2 ref={elementRef => { this.titleRef = elementRef }}></h2>
// 通过this.titleRef获取DOM结构
可以通过**ref**
获取组件实例
import React, { PureComponent, createRef } from 'react'
class HelloWorld extends React.PureComponent {
test() {
console.log('HelloWorld组件的test方法')
}
render() {
return <h2>HelloWorld</h2>
}
}
export class App extends PureComponent {
constructor(props) {
super(props)
this.componentRef = createRef()
}
getComponent() {
console.log(this.componentRef.current)
this.componentRef.current.test()
}
render() {
return (
<div>
<HelloWorld ref={this.componentRef}/>
<button onClick={ e => this.getComponent()}>获取组件实例</button>
</div>
)
}
}
export default App
forwordRef获取函数组件DOM
import React, { PureComponent, createRef, forwardRef } from 'react'
const HelloWorld = forwardRef(function(props, ref) {
return (
<div>
<h1 ref={ref}>Hello World</h1>
<p>哈哈哈</p>
</div>
)
})
export class App extends PureComponent {
constructor() {
super()
this.hwRef = createRef()
}
getComponent() {
console.log(this.hwRef.current) // <h1>Hello World</h1>
}
render() {
return (
<div>
<HelloWorld ref={this.hwRef}/>
<button onClick={e => this.getComponent()}>获取组件实例</button>
</div>
)
}
}
export default App
受控组件与非受控组件
受控组件
import React, { PureComponent } from 'react'
export class App extends PureComponent {
constructor() {
super()
this.state = {
username: "nannan"
}
}
inputChange(event) {
// console.log("inputChange:", event.target.value)
this.setState({ username: event.target.value })
}
render() {
const { username } = this.state
return (
<div>
{/* 受控组件 */}
<input type="input" value={username} onChange={e => this.inputChange(e)}/>
{/* 非受控组件 */}
<input type="text" />
<h2>username: {username}</h2>
</div>
)
}
}
export default App
handleSumbitClick(event) {
event.preventDefault()
}
handleUsernameChange(event) {
this.setState({
username: event.target.value
})
}
handleChange(event) {
// const name = event.target.name
this.setState({
[event.target.name]: event.target.value
})
}
// label标签的for转换为htmlFor
<form onSubmit={e => this.handleSubmitClick(e)}>
<input type="text" id="username" name="username" value={username}
onChange={e => handleUsernameChange(e)}
/>
<button type="submit">submit</button>
</form>
state= {
isAgree: true
}
handleChange(event) {
this.setState({
isAgree: event.target.checked
})
}
<input type="checkbox"
checked={isAgree} id="agree"
onChange={e => this.handleChange(e)}
/>
state = {
hobbies: [
{ value: 'sing', text: '唱', isChecked: false},
{ value: 'dance', text: '跳', isChecked: false},
{ value: 'rap', text: 'rap', isChecked: false},
]
}
handleHobbiesChange(event,index) {
const hobbies = [...this.state.hobbies]
hobbies[index].isChecked = event.target.checked
this.setState({ hobbies })
this.state.hobbies.filter(item => item.isChecked).map(item => item.value)
state = {
// fruit: '',
fruit: ['orange']
}
handle FruitChange(event) {
this.setState({
fruit: event.target.value
})
// Array.from(可迭代对象,mapfn)
const options = Array.from(event.target.selectOptions)
const values = options.map(item => item.value)
// Array.from(arguments)
// const values2 = Array.from(event.target.selectOptions, item => item.value)
this.setState({ fruit: values })
}
<select value={this.state.fruit} onChange={ e => this.handleFruitChange(e)} multiple>
<option value="apple">苹果</option>
<option value="orange">橘子</option>
</select>
非受控组件
在非受控组件中通过**defaultValue**
来设置默认值
<input type="text" defaultValue={defaultName} ref={this.nameRef} />
// console.log("获取结果:", this.nameRef.current.value)
高阶组件
高阶组件的定义
接收一个函数作为参数或者返回一个函数作为结果的函数叫做**高阶函数**
**高阶组件式参数为组件,返回值为新组件的函数**
function hoc(Cpn) {
class newCpn extends PureComponent {
state = {
info: {
name: 'zzf',
age: 22
}
}
render() {
return <Cpn {...this.state.info}/>
}
// 组件的名称可以通过displayName来修改
newCpn.displayName = 'newComponent'
return newCpn
}
高阶组件在一些React第三方库中会非常常见:
- Redux中的connect
-
高阶组件的使用场景
增强props
- context
- 登录鉴权
function loginAuth(OriginComponent) { return props => { const token = localStorage.getItem("token") if (token) { return <OriginComponent {...props}/> } else { return <h2>请先登录</h2> } } }
Portals的使用
```javascript import { createPortal } from ‘react-dom’
{
createPortal(
<a name="wdx2w"></a>
### Fragment
但是,如果我们需要在Fragment中添加key,那么就不能使用短语法
```jsx
<Fragment>
<h2>content</h2>
</Fragment>
// <><h2>content</h2></>
StrictMode
StrictMode 是一个用来突出显示应用程序中潜在问题的工具:
- 识别不安全的生命周期
- 使用过时的
**ref**
API - 检查意外的副作用
- 使用废弃的findDOMNode方法
- 检查过时的
**context**
API<React.StrictMode></React.StrictMode>