react——hooks(拓展hook之useImperativeHandle、useLayoutEffect、useDebugValue)

React Hooks

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

7.useImperativeHandle

useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle 应当与 forwardRef 一起使用:

1
2
3
4
5
6
7
8
9
10
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);

在本例中,渲染 <FancyInput ref={inputRef} /> 的父组件可以调用 inputRef.current.focus()

8.useLayoutEffect

1.useEffect会在渲染的内容更新到DOM上后执行,不会阻塞DOM的更新
2.useLayoutEffect会在渲染的内容更新到DOM上之前进行,会阻塞DOM的更新

其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。

尽可能使用标准的 useEffect 以避免阻塞视觉更新。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, {useState, useEffect, useLayoutEffect} from 'react'

export default function UseLayoutEffect() {

const [count,setCount] = useState(10)

useLayoutEffect(()=>{
if(count ===0){
setCount(Math.random())
}
},[count])
return (
<div>
<h2>数字:{count}</h2>
<button onClick={e=>setCount(0)}>修改数字</button>
</div>
)
}

我们把count变成一个随机数, 虽然可以实现,但是当我们点击修改的时候其实是有一个闪烁的 因为它先把数字变为了0,再变成了随机数

但是当我们这样写把里面的useEffect换成了useLayoutEffect,页面就不会发生这个闪烁了,这个useLayoutEffect其实在开发中不太常用,一些特殊情况才会用。

9.useDebugValue

useDebugValue 可用于在 React 开发者工具中显示自定义 hook 的标签。

1
2
3
4
5
6
7
8
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);

// ...

// 在开发者工具中的这个 Hook 旁边显示标签 // e.g. "FriendStatus: Online" useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}

在某些情况下,格式化值的显示可能是一项开销很大的操作。除非需要检查 Hook,否则没有必要这么做。

因此,useDebugValue 接受一个格式化函数作为可选的第二个参数。该函数只有在 Hook 被检查时才会被调用。它接受 debug 值作为参数,并且会返回一个格式化的显示值。

例如,一个返回 Date 值的自定义 Hook 可以通过格式化函数来避免不必要的 toDateString 函数调用:

1
useDebugValue(date, date => date.toDateString());