React Recoil下Overlay封装优化:简化重复try-finally逻辑的方案问询
基于Recoil封装全局遮罩的withOverlay工具函数方案
核心思路
React Hooks仅允许在组件或自定义Hooks中调用,因此我们可以通过自定义Hook封装withOverlay函数,让它闭包Recoil的状态设置方法,从而在组件中安全调用,同时避免重复代码。
实现步骤
1. 定义Recoil状态Atom
先定义Overlay的状态Atom,可选择基础单请求版或支持多并发请求的进阶版:
import { atom } from 'recoil'; // 基础版:单请求遮罩 export const overlayState = atom({ key: 'overlayState', default: { visible: false, text: '加载中...' }, }); // 进阶版:支持多并发请求(推荐) // export const overlayState = atom({ // key: 'overlayState', // default: { count: 0, text: '加载中...' }, // });
2. 封装自定义Hook返回withOverlay
在自定义Hook中获取Recoil的状态设置方法,封装withOverlay工具函数:
import { useSetRecoilState } from 'recoil'; import { overlayState } from './path-to-your-atom'; export function useOverlay() { const setOverlay = useSetRecoilState(overlayState); // 基础版:单请求处理逻辑 const withOverlay = async (asyncFn, text = '加载中...') => { try { setOverlay({ visible: true, text }); return await asyncFn(); } finally { setOverlay({ visible: false, text: '' }); } }; // 进阶版:多并发请求处理逻辑(替换上面的基础版即可) // const withOverlay = async (asyncFn, text = '加载中...') => { // try { // setOverlay(prev => ({ // count: prev.count + 1, // // 仅第一个请求设置提示文本,后续请求保留当前文本 // text: prev.count === 0 ? text : prev.text // })); // return await asyncFn(); // } finally { // setOverlay(prev => ({ // count: Math.max(prev.count - 1, 0), // // 最后一个请求结束后清空文本 // text: prev.count === 1 ? '' : prev.text // })); // } // }; return { withOverlay }; }
3. 在组件中调用withOverlay
在业务组件中引入自定义Hook,直接用withOverlay包裹异步操作:
import { useOverlay } from './useOverlay'; function SubmitComponent() { const { withOverlay } = useOverlay(); const handleSubmit = async () => { try { const response = await withOverlay( async () => await myApi.post({ data: 'test' }), '提交数据中...' ); // 处理请求成功逻辑 console.log('提交成功:', response); } catch (error) { // 处理请求失败逻辑 console.error('提交失败:', error); } }; return <button onClick={handleSubmit}>提交</button>; }
4. 全局遮罩组件适配(进阶版)
如果使用了计数版Atom,全局遮罩组件需根据计数判断是否显示:
import { useRecoilValue } from 'recoil'; import { overlayState } from './path-to-your-atom'; export function GlobalOverlay() { const { count, text } = useRecoilValue(overlayState); if (count === 0) return null; return ( <div style={{ position: 'fixed', top: 0, left: 0, width: '100%', height: '100%', backgroundColor: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: '16px' }}> {text} </div> ); }
方案合理性说明
自定义Hook是React官方允许的Hooks使用场景,useOverlay中调用useSetRecoilState完全符合规则;返回的withOverlay函数通过闭包持有状态设置方法,在组件中调用时不会触发Hooks规则报错,同时实现了代码复用。
内容的提问来源于stack exchange,提问作者JaktensTid
相关产品推荐
相关产品推荐

