hook简介
- hook 是React 16.8 的新特性,使函数组件更强大
- 优点
- 可以在不编写 class 的情况下使用
state 以及其他的 React 特性 - 解决业务逻辑难拆分的问题
- 方便状态逻辑复用
- 注意点
- hook和class写法共存
- hook只能在函数组件中使用
基础hook
useState
-
为函数组件提供数据状态(state) -
const [count,setCount] = useState(0)
count:使用的数据
setCount:修改数据的对应方法
-
注意点
-
useState的初始参数只会在组件首次渲染时使用,再次更新时会被忽略 -
每次通过 setCount 修改状态都会引起组件重新渲染 -
useState 可以调用多次,每次都是独立的 -
useState 不可以在函数组件之外的地方执行 -
如果初始值需要计算才能得到,那可以使用回调函数写法
useEffect
-
作用
- 发送网络请求
localstorage 操作- 监听数据修改
UI - 手动修改
DOM -
执行时机
- 默认状态:首次执行+每次组件更新时执行
- 添加空数组([]) : 首次执行
- 添加需要监听的数据: 首次执行+监听数据变化时执行
-
清除副作用 :数据渲染 UI 之外的操作
-
useEffect(()=>{
return()=>{
//清理副作用
//例如:清除定时器等
}
})
useContext
- 作用:在
hook 下跨组件传递数据 - 实现步骤
- 使用
createContext 创建 Context 对象 - 在顶层组件通过
Provider 提供数据 - 在底层组件通过
useContext 函数获取数据
额外的 hook
useRef
-
作用:获取真实的 DOM 或者组件实例对象 -
实现步骤
-
导入useRef 函数 -
执行 useRef 函数并传入 null,返回值为一个对象,内部有一个current属性存放 DOM 对象(组件实例) -
通过 ref 绑定获取元素或者组件
-
const divRef = useRef()
<div ref={divRef}></div>
useImperativeHandle
-
作用:在使用ref 时自定义暴露父组件的实例值 -
实现步骤
- 给子组件绑定
useRef 属性 - 在子组件中导入
forwardRef ,包裹子页面顶层组件;包裹后第一个参数是props 属性,第二个参数是ref 属性 - 导入
useImperativeHandle ,有三个参数
- 第一个参数:
ref - 第二个参数: 返回值;需要在父页面操作的dom,
- 第三个参数:数组依赖项;控制
useImperativeHandle 返回值是否刷新 - 补充:
- 导入
useImperativeHandle 后可以通过返回控制子组件的全部ref ; useImperativeHandle ,返回值可以返回多种类型forwardRef ,只能控制一个 -
代码实现
-
//父页面
import {useRef} from "react"
import ImperaciveHandle from "@/components/hooks/ImperativeHandle.jsx"
const App()=>{
const fatherRef = useRef()
return (
<div>
// 操作子组件实例
<button onClick={()=> {
fatherRef.current.userRef.current.focus()
}}>聚焦输入框</button>
<button onClick={()=> {
fatherRef.current.passwordRef.current.focus()
}}>聚焦密码</button>
<ImperaciveHandle ref={fatherRef}/>
</div>
)
}
export default App;
-
// 子组件
import { useRef, forwardRef ,useImperativeHandle} from "react"
// 1. 使用 forwardRef ,包裹页面组件,包裹后组件参数,第一个是props,第二个是ref
const ImperaciveHandle = ({},ref) => {
const userRef = useRef()
const passwordRef = useRef()
// 2.将需要父组件操控的dom,通过 useImperativeHandle 返回
useImperativeHandle(ref,()=>{
// 这里可以返回数组,对象,字符串,jsx等
return {
userRef,
passwordRef,
}
//[]:依赖项控制 useImperativeHandle 返回值是否刷新
},[])
return (
<div>
<input type="text" placeholder="用户名" ref={userRef} />
<input type="password" placeholder="密码" ref={passwordRef} />
</div>
)
}
export default forwardRef(ImperaciveHandle)
-
以上通过 useImperativeHandle 实现焦点控制
useMemo
-
作用:监听子组件变化来处理事件,优化子组件渲染 -
useMemo 有两个参数,
1. 第一个参数是函数;
2. 第二个参数是数组,用来监听某个状态不改变,状态不改变,函数就不会执行,除了首次渲染时
-
import React, { useState, useMemo } from 'react';
const Child = ({ age, name, children }) => {
//在不用useMemo做处理的时候,只要父组件状态改变了,子组件都会渲染一次;
//用了useMemo可以监听某个状态name,当name变化时候执行useMemo里第一个函数,
console.log('子组件渲染');
function namechange() {
console.log('子组件内部函数');
return name + 'change';
}
//useMemo有两个参数,和useEffect一样,第一个参数是函数,第二个参数是个数组,用来监听某个状态不变化
const changedname = useMemo(() => namechange(), [ name ]);
return (
<div style={{ border: '1px solid' }}>
<p>children:{children}</p>
<p>name:{name}</p>
<p>age:{age}</p>
<br />
{/* 子组件函数 */}
<p>changed:{changedname}</p>
</div>
);
};
const UseMemo = () => {
const [ name, setName ] = useState('张三');
const [ age, setage ] = useState(20);
return (
<div>
<button
onClick={() => {
setname('张三' + new Date().getTime());
}}
>name</button>
<button
onClick={() => {
setage('年龄' + new Date().getTime());
}}
>age</button>
<p>父组件的:{name}--{age}</p>
<Child age={age} name={name}>
{name}的children
</Child>
</div>
);
};
```
|