> 文章列表 > 【react】react18的学习(三)--hooks组件

【react】react18的学习(三)--hooks组件

【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