react hooks
useState#
setState 可以设置具体的值,也可以通过函数,利用先前的值计算得出
setState(prevState => {
// 也可以使用 Object.assign
return {...prevState, ...updatedValues};
});
useEffect#
若在 useEffect
中使用 useState
, 那么 useEffect
的第二个条件参数(依赖项)不能设置对象,否则进入死循环。因为若设置对象,则每次都会进入到 useEffect
中,由于在 useEffect
中调用 setState
,则会导致页面重新渲染,而页面重新渲染,就又会进入到 useEffect
中......
useReducer#
const [state, dispatch] = useReducer(reducer, initialArg, init);
它是 useState 的替换方案。
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
useDispatch & useSelector: 可以完全代替 redux#
import { useDispatch, useSelector } from 'dva';
const dispatch = useDispatch();
// 从model仓库中取数据
const { projectList } = useSelector((state) => state.appInfo);
const appInfo = useSelector((state) => state.appInfo);
useCallback / useMemo#
用于缓存数据,优化性能的钩子函数,
useCallback(fn, deps)
相当于 useMemo(() => fn, deps)
。
共同作用:
当依赖数据发生变化时,才会调用传进去的回调函数去重新计算结果,起到一个缓存的作用
不同作用:
- useMemo 缓存的结果是回调函数中return回来的值,主要用于缓存计算结果的值,应用场景如需要计算的状态
- useCallback 缓存的结果是函数,主要用于缓存函数。但它需要和React.memo 配套使用,缺少任意一个都可能导致性能不升反降
useCallback#
用于某函数无需反复渲染。
map.addEventListener('rightclick', onRightClick);
const onRightClick = useCallback(() => {
const markerMenu = new BMap.ContextMenu();
markerMenu.addItem(
new BMap.MenuItem('设为终点', (e) => {
const geoc = new BMap.Geocoder();
let address = '';
}),
);
map.addContextMenu(markerMenu);
}, [map]);
useMemo#
相当于class组件的 pureComponent
, 可以缓存整个函数组件
useRef#
const refContainer = useRef(initialValue);
useRef 返回一个可变的 ref 对象,其 .current
属性被初始化为传入的参数(initialValue
)。返回的 ref 对象在组件的整个生命周期内保持不变。
三种用法:
(一):命令式的访问子组件
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
(二):非常方便的保存任何值
const draggingRef = useRef(null);
const handleDragStart = e => {
e.stopPropagation?.();
draggingRef.current = e.currentTarget;
};
const formRef = useRef(null);
useEffect(() => {
formRef.current = form;
}, [form]);
useEffect(() => {
dispatch({
type: `${currentModel}/overrideStateProps`,
payload: {
accessoryInfoForm: formRef,
},
});
}, [dispatch, formRef, currentModel]);
(三):访问DOM的主要方式
将 ref 对象以 <div ref={myRef} />
形式传入组件,则无论该节点如何改变,React 都会将 ref 对象的 .current
属性设置为相应的 DOM 节点。
当 ref 对象内容发生变化时,
useRef
并不会通知你。变更.current
属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。
useImperativeHandle#
useImperativeHandle
可以让我们在使用 ref 时自定义暴露给父组件的实例值,即有选择性的暴露出去,而不是全部暴露。
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
useLayoutEffect#
和 useEffect
用法一样。但 useEffect
有延迟,而 useLayoutEffect
没有延迟,它在读取DOM布局后就同步触发重渲染。即:在浏览器执行绘制之前,useLayoutEffect
内部的更新计划将被同步刷新。
一开始先用
useEffect
,只有当它出问题的时候再尝试使用useLayoutEffect
若要从服务端渲染的 HTML 中排除依赖布局 effect 的组件,可以通过使用
showChild && <Child />
进行条件渲染,并使用useEffect(() => { setShowChild(true); }, [])
延迟展示组件。这样,在客户端渲染完成之前,UI 就不会像之前那样显示错乱了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~