默认情况下,React函数组件是没有状态
state
的、没有生命周期的。react16版本后,新增了useState
和useEffect
等钩子函数,让现在的函数组件具有了之前类组件的同等效力。解决了类组件在实际开发中的一些痛点
让函数组件拥有了状态,类似Vue中的ref、reative。开发中,为了让数据更新视图,才会赋予这个数据以状态,否则这个数据还是作为普通局部变量的好
import { useState } from 'react'
const Home = () => {
const [count, setCount] = useState(0)
const add = () => {
setCount(count + 1)
}
return (
<>
<span>{count}</span>
<button onClick={add}>+</button>
</>
)
}
export default Home
注意: setCount会更新组件
让函数组件拥有生命周期,
useEffect
hook即是:类组件中componentDidMount、componentDidUpdate、componentWillUnmounted这三个钩子的功能组合
import { useState, useEffect } from 'react'
const Home = () => {
const [count, setCount] = useState(0)
const add = () => {
setCount(count + 1)
}
// 接收一个参数时:组件加载完成和组件状态更新时 执行
useEffect(function () {
console.log('zhw')
})
// 如果只希望函数挂载完后,执行一次,组件状态变化不再执行,可以传空数组
useEffect(function () {
console.log('zhw')
}, [])
// 接收参数二时,参数二是一个数组,用于指定依赖数据,用于当依赖数据变化时,执行一次回调
// 1、组件挂载完后执行一次;2、仅仅当count的状态更新,执行一次
useEffect(function () {
console.log('zhw')
}, [count])
// 组件卸载之前按
// 1、
useEffect(function () {
return function () {
// 该子函数会在组件 即将卸载 和 状态更新 的时候,自动执行
console.log('组件卸载了')
}
})
// 2、
useEffect(function () {
return function () {
// 该子函数会在组件 仅仅在 即将卸载 的时候,自动执行
console.log('组件卸载了')
}
}, [])
return (
<>
<span>{count}</span>
<button onClick={add}>+</button>
</>
)
}
export default Home
允许在函数组件中使用ref属性 操作元素或者组件对象,useRef底层使用的就是createRef
import React, { useState, useRef } from 'react'
const Home = () => {
const [count, setCount] = useState(0)
// React.MutableRefObject: 因为numRef 可能undefined
const numRef = useRef() as React.MutableRefObject<HTMLHtmlElement>
const add = () => {
setCount(count + 1)
// useRef().current: 获取元素或者组件对象
console.log(numRef.current)
}
return (
<>
<button onClick={add}>+</button>
<span ref={numRef}>{count}</span>
</>
)
}
export default Home
只需借用ref属性,不需要使用useRef()
const Home = () => {
const hobbies = ['唱跳', 'rap', '篮球']
// 这块使用普通对象
const hobbyRefList: HTMLElement[] = []
const getHobbyEle = () => {
// 更新rap背景色
hobbyRefList[1].style.background = 'skyblue'
}
return (
<>
<ul>
{hobbies.map((item) => (
<li
ref={(el: HTMLLIElement) => {
hobbyRefList.push(el)
}}
key={item}
>
{item}
</li>
))}
</ul>
<button onClick={getHobbyEle}>获取爱好列表元素对象</button>
</>
)
}
export default Home
react18中无法直接通过ref属性获取组件对象,因为react18中,函数组件没有实例。直接使用ref会报错:
Function components cannot be given refs
。既然无法获取实例,则需要想其他办法,获取组件状态和方法.此时可以使用React内置的高阶组件
:React.forwardRef
: 用于处理函数组件,可以将ref属性传递到函数组件内部
子组件中
import { useState, forwardRef, useImperativeHandle } from 'react'
// props: 父组件通过自定义属性传递的数据
// ref: 把父组件传递的ref属性和函数子组件元素建立对应关系
const Header = (props: object, ref: any) => {
console.log(props, ref)
const [title, setTitle] = useState('头部组件')
// 用于子组件 向父组件 暴露方法
// 类似于Vue3的 defineExpose
useImperativeHandle(ref, () => ({
updateTitle: (title: string) => {
setTitle(title)
}
}))
return (
<>
<div ref={ref}>{title}</div>
</>
)
}
export default forwardRef(Header)
关键词: forwardRef
和 useImperativeHandle
父组件中
import { useRef } from 'react'
import Header from '@/components/Header'
const Home = () => {
// useRef利用泛型 可以自动推导类型为: React.MutableRefObject
// 解决: 类型“(instance: HTMLDivElement | null) => void”上不存在属性“current”
const funCompRef = useRef<HTMLElement>()
const getHobbyEle = () => {
console.log(funCompRef.current)
}
return (
<>
<Header ref={funCompRef} />
<button onClick={getHobbyEle}>获取爱好列表元素对象</button>
</>
)
}
export default Home