跳到主内容

React基础面试题之hooks

hooks 可以在函数组件里面声明自身状态,实现跟类组件一样的生命周期。给开发者带来更良好的编写组件体验。

常见的 hooks 有哪些?

基础 hooks 有useStateuseEffectuseContextuseReduceruseRefuseMemouseCallbackuseLayoutEffectuseImperativeHandleuseDebugValue

useLayoutEffect 有什么用?

useLayoutEffect 在浏览器绘制之前调用,一般用它来同步更新 DOM 并渲染,等同于 componentDidUpdatecomponentDidMount

在服务端不能使用这个 hooks,不然会报以下错误

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://fb.me/react-uselayouteffect-ssr for common fixes.

解决方法很简单,自定义条件 Effect

import { useEffect, useLayoutEffect } from "react";
export const useCustomLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;

建议使用 useEffect!建议使用 useEffect!建议使用 useEffect! 避免阻塞视觉更新。

useEffect 和 useLayoutEffect 的区别?

  1. useEffect 是在渲染时异步执行,等到浏览器将所有变化渲染到屏幕后才会被执行。在本次更新完成后,再开启一个任务调度,在下次任务调度中执行。

  2. useLayoutEffectcomponentDidMountcomponentDidUpdate 执行时机一样,并且是同步执行的。在浏览器将所有变化渲染到屏幕之前执行。

useImperativeHandle 有什么用?

useImperativeHandle函数签名如下

useImperativeHandle(ref, createHandle, [deps]);

useImperativeHandle 可以自定义暴露给父组件的实例属性或者方法,通常与 forwardRef 配合使用,其实就是防止 forwardRef 暴露过多的组件实例方法或属性给父组件,导致不可预知的错误

function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}

FancyInput = forwardRef(FancyInput);

class App extends React.Component {

constructor(props) {
this.inputRef = React.createRef(null);
}

componentDidMount() {
// 在此处调用foucus方法
this.inputRef.current.focus();
}

render() {
<div>
<FancyInput ref={this.inputRef} />
</div>
}
}

hooks 有哪些注意事项

  1. 不要在循环,条件或嵌套函数中调用 Hook,必须始终在 React 函数的顶层使用 Hook。这是因为 React 需要利用调用顺序来正确更新相应的状态,以及调用相应的钩子函数。一旦在循环或条件分支语句中调用 Hook,就容易导致调用顺序的不一致性,从而产生难以预料到的后果。

  2. 只能在 React 函数式组件或自定义 Hook 中使用 Hook。