React(二)

setState其他用法
  • setState({})
  • setState((state,props)=> { return {} })
  • setState(updater,callback)
React为什么使用setState
  • React并没有实现类似于Vue2中的Object.defineProperty或者Vue3中的Proxy的方式来监听数据的变化

  • 必须通过setState来告知React数据已经发生变化

  • setState方法是从React.Component中继承

  • 异步调用

    • 批量更新,提升性能
  • 本次更新会加入队列中queue

  • 两个优势

    • 多个updater放在同一次更新中,执行一次render函数,提高性能
    • 保证在state没有被更新的时候,state、props保持一致
  • setState一定是异步的吗?

    • 在react18之前

      • setTimeout/Promise.then回调/原生DOM事件回调中是同步的
    • 在react18开始

      • setTimeout/Promise.then回调/原生DOM事件回调中也变成批量处理
      • flushSync( ()=> {} ) 强制 React 刷新任何挂起的工作并同步更新 DOM
React的更新流程
  • props、state发生改变
  • render函数重新执行
  • 生成新的DOM树
  • 新旧DOM数进行diff
  • 计算出差异进行更新
  • 更新到真实的DOM
Render函数被调用
  • render函数的优化
    • shouldComponentUpdate(SCU)
      • 参数1:nextProps
      • 参数2:nextState
      • 返回true 调用当前组件的render函数、默认返回true
  • PureComponent
    • 类组件继承
    • 自动对state、props进行判断修改
    • 浅层比较 shallowEqual
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React,{ PureComponent } from 'react'
class Chidlren extends PureComponent {
constructor() {
super()

this.state = {
str:''
}
}
render() {
return <>
hello,PureComponent
</>
}
}
  • 函数组件没有声明周期
    • memo 作用等同于 PureComponent
  • 在props没有改变时,不希望重新渲染期DOM树结构
1
2
3
4
import { memo } from 'react'
const Children = memo(function(props){
return <>hello,memo</>
})
state应该是不可变的
  • 修改state中的某一个数据(引用类型)
    • 先拷贝其数据,修改拷贝对象,设置新对象
ref获取DOM
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 三种获取DOM的方法
import React, { PureComponent, createRef } from 'react'

export class Children extends PureComponent {
constructor() {
super()

this.state = {
divRef1: this.ref.divRef1, // 已废弃
divRef2: createRef(), // this.state.divRef2.current
divRef3: null
}

}
render() {
return (
<>
<div ref='divRef1'>hello,ref1</div>
<div ref={this.state.divRef2}>hello,ref2</div>
<div ref={el => this.state.divRef3 = el}>hello,ref3</div>
</>
)
}
}

export default Children
  • ref不能应用于函数式组件
    • 因为函数式组件没有实例,所以不能获取到对应的组件对象
    • 可以通过forwardRef
1
2
3
4
5
6
7
8
// 转发
const Home = forwarRef(function(props,ref) {
return (
<div>
<h2 ref={ref}>Home</h2>
</div>
)
})
受控组件
  • 被React以state方式控制取值的表单输入元素就叫做受控组件
非受控组件
  • 表单数据交给DOM节点来处理
  • ref获取元素
高阶组件
  • HOC Higher-Order Components
  • 参数为组件,返回值为新组件的函数
  • props增强
  • context增强
Portals的使用
  • 如果希望渲染的内容独立于父组件,甚至是独立于当前挂载到的DOM元素中
1
2
3
import { createPortal } from "react-dom";

createPortal(<Children4/>,document.querySelector('#cy'))
fragement
1
2
3
<Fragement></Fragement> // 需要绑定key的时候不能省

<></>
StrictMode
  • 识别不安全的声明周期
  • 使用过时的ref API
  • 检查意外的副作用
    • 这个组件的constructor会被调用两次
  • 使用废弃的findDOMNode方法
  • 检测过时的context API
1
2
3
<StrictMode>
<App/>
</StrictMode>
过渡动画
  • react-transition-group
  • CSSTransition
    • -enter
    • -enter-done
  • unmountOnExit={true}
    • 该组件会在执行退出动画结束后被移除掉
  • 当in为true时,触发进入状态
  • 当in为false时,触发退出状态
  • timeout 移除时间
  • appear 首次出现添加动画
    • -appear
  • onEnter | onEntering | onEntered 钩子函数
css
  • 内联样式
    • style接收一个采用小驼峰命名属性的JS对象,而不是CSS字符串
  • 普通CSS
    • 没有单独作用域,样式冲突
  • CSS Modules
    • 不能使用连接符 appStyle.my-title
    • 所有的className都必须使用{style.className}的形式来编写
      • 不方便动态修改某些样式,依然需要使用内联样式
1
2
3
4
5
App.module.css

import appStyle from './App.module.css'

<div style={appStyle.title}>hello</div>
  • CSS -in-JS 第三方库
    • styled-components

    • emotion-js/emotion

    • glamorous

    • classnames