【react】react18的学习(三)--hooks组件
上一篇:【react】react18的学习(二)
1、useState:使函数组件可以使用并修改 state
import { useState } from 'react'
let [num, setNum] = useState(0)
// 常见写法
useState(0)
// 初始值比较复杂时
useState(()=>{return })
setNum(10)
// 获取更新前数据
setNum(pre => {return pre + 1
})
- 与类组件的
setState()
不同,不支持部分修改;所以推荐每个变量对应一个useState
; - 18中都是异步,多次fun会统一渲染;
- 16版本中,也与setState一致,多次执行时,在合成事件、周期函数中是异步渲染(react处理),在其他异步操作中:如定时器、手动事件绑定等没有react干预是依次同步渲染;
- 特别地,自带优化,当修改的值与之前的值一样时(Object.is),不重新渲染;
// useState返回值是一个数组[0,fun],用解构接收,其中方法传参就是修改后的值
import { useState } from 'react'let [num, setNum] = useState(0)//num:0const handle = () => {setNum(10)// num:10}
// 多个变量分开,便于维护const [num0, setNum0] = useState(10)const [num1, setNum1] = useState(10)
- 如何实现循环渲染:fun的传参:
for (let i = 0; i < 10; i++) {setNum(pre => {return pre + 1})}
// 类组件中setState循环state = {num: 0,}handle = () => {for (let i = 0; i < 10; i++) {this.setState(pre => {return { num: pre.num + 1 }})}}
- 初始值使用函数:当初始值比较复杂时使用
// 初始值使用函数返回,可以避免多次渲染时重复执行初始化过程
const [num0, setNum0] = useState(()=>{return})
2、useEffect:使函数组件可以使用 生命周期
- 写法1:useEffect(() => {}),相当于
componentDidMount、componentDidUpdate
- 写法2:useEffect(() => {},[]),只相当于
componentDidMount
,状态更新不执行 - 写法3:useEffect(() => {},[num]),同1,需要在num状态更新时才执行;
- 写法4:useEffect(() => { return ()=>{}}),相当于执行上一次组件销毁前钩子
componentWillUnmount
,首次渲染不执行; - 写法5:useEffect(() => { return ()=>{}},[]),无效
- 写法6:useEffect(() => { return ()=>{}},[num]),同4,在执行依赖项改变时有效;
import { useState, useEffect } from 'react' useEffect(() => {console.log('钩子:', props)},[])useEffect(() => {return () => {console.log('钩子:', props)}},[])
- 多个useEffect存放在
effect链表
中,等待视图挂载后依次执行;
3、useLayoutEffect
- 用法与
useEffect
一样,都能获取到真实DOM对象; - 区别:比
useEffect
早一步执行,是在root.render()
将虚拟dom解析出来真实dom对象后执行,此时浏览器还没有绘制, useEffect
:异步操作,与浏览器绘制渲染同时进行,官方更推荐使用;useLayoutEffect
:同步操作,在浏览器绘制渲染之前进行,内部如果更改状态,会阻止本次浏览器绘制,先去重新渲染组件再统一绘制;
useLayoutEffect(() => {if (num == 0) {setNum(10)}console.log(document.getElementById('aa'))}, [num])
4、useRef:使函数组件可以使用 ref
- ref:用于获取标签元素、组件实例
- 模仿类组件的两种方式:
// 函数方式let boxuseEffect(() => {console.log(box)}, [])return (<div ref={x => (box = x)}>
// React.createRef()方式let box = React.createRef()useEffect(() => {console.log(box.current)}, [])return (<div ref={box}>
- 等价于
React.createRef()
方式
let box = useRef(null)useEffect(() => {console.log(box.current)}, [])return (<div ref={box}>
-
为什么还需要
useRef
:每次更新组件,拿到的ref对象都是原来的,而
React.createRef()
每次执行都重新创建,这一点对类组件没影响,因为类组件每次渲染是执行的render()
函数,不会重新执行React.createRef()
; -
获取hooks组件内状态
const Demo = React.forwardRef((props, ref) => {const [num, setNum] = useState(0);useImperativeHandle(ref, () => {return { num }// 这个对象将替掉返回的标签:{num:0}或{current:{num:0}}})
- antd组件库中自有的获取form元素方式
// let form = useRef(null)
let [formIns] = Form.useForm()
----
<Form// ref={form} // form.currentform={formIns} //直接:formIns