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**`来包裹该组件```javascriptimport { 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.statereturn (<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.namethis.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.checkedthis.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>
