React基础面试题之hooks
hooks 可以在函数组件里面声明自身状态,实现跟类组件一样的生命周期。给开发者带来更良好的编写组件体验。
常见的 hooks 有哪些?
基础 hooks 有useState
,useEffect
,useContext
,useReducer
,useRef
,useMemo
,useCallback
,useLayoutEffect
,useImperativeHandle
,useDebugValue
。
useLayoutEffect 有什么用?
useLayoutEffect
在浏览器绘制之前调用,一般用它来同步更新 DOM 并渲染,等同于 componentDidUpdate
,componentDidMount
在服务端不能使用这个 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 的区别?
useEffect
是在渲染时异步执行,等到浏览器将所有变化渲染到屏幕后才会被执行。在本次更新完成后,再开启一个任务调度,在下次任务调度中执行。useLayoutEffect
和componentDidMount
,componentDidUpdate
执行时机一样,并且是同步执行的。在浏览器将所有变化渲染到屏幕之前执行。
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 解决了哪些问题
- 组件之间逻辑或者状态复用(共享状态逻辑),旧的实现方式是用
render props
或者高阶组件。 - 复杂组件难以理解,例如在生命周期钩子里面处理事件,状态逻辑,代码冗余到一起,容易产生 bug,而 hooks 将组件关联部分拆分成更小的函数(事件订阅和请求数据隔离)而无需按照生命周期划分。-
- 难以理解的 class 类组件 this 指向问题,需要用箭头函数或者
bind
方法处理
hooks 有哪些注意事项
不要在循环,条件或嵌套函数中调用 Hook,必须始终在 React 函数的顶层使用 Hook。这是因为 React 需要利用调用顺序来正确更新相应的状态,以及调用相应的钩子函数。一旦在循环或条件分支语句中调用 Hook,就容易导致调用顺序的不一致性,从而产生难以预料到的后果。
只能在 React 函数式组件或自定义 Hook 中使用 Hook。