React Custom Hooks错误处理咨询:回调处理错误是否属于反模式
问题1:我的这套实现方案是否合理?
你的实现方案是合理的。你对关注点分离的判断完全正确:业务Hook的核心职责是处理数据请求、状态维护、请求防抖等和业务逻辑强相关的内容,和UI渲染强耦合的toast调用、国际化翻译等逻辑确实不应该侵入业务Hook,你目前将UI层逻辑放在组件内处理的思路符合单一职责原则,可维护性更高。
问题2:在hooks中用回调处理错误的方式是否属于反模式?
这不属于反模式。回调是异步副作用结果处理的经典实现方式之一,在自定义请求Hook的场景下,回调方案反而给了调用方极高的灵活性:你既可以选择在组件层处理错误弹toast,也可以选择将错误透传给上层错误边界,还可以给同一个请求Hook在不同组件内配置不同的错误处理逻辑(比如部分场景下不弹toast,直接在页面内渲染错误占位UI),灵活性远高于把错误处理逻辑写死在业务Hook内。
问题3:这种场景下的通用处理方案是什么?
除了你目前在用的回调方案外,还有两种业界常用的实现方式可以选择:
方案1:抽离公共错误处理Hook优化现有回调方案
你可以把重复的toast调用、国际化翻译逻辑抽成通用的错误处理Hook,减少组件内的重复代码:
// 公共错误处理Hook const useRequestErrorHandler = () => { const toast = useToast() const { t } = useTranslation() const handleRequestError = (err) => { toast.display(t(err), { type: "error", duration: 500 }) } return { handleRequestError } } // 组件内使用 function MyComponent() { const { handleRequestError } = useRequestErrorHandler() const { data, isLoading, requestSomething } = useRequestSomething() const handleOnPress = () => { requestSomething("x", undefined, handleRequestError) } // ... 剩余JSX逻辑 }
方案2:暴露错误状态,使用声明式监听逻辑
你可以修改业务Hook,将错误作为状态对外暴露,组件内通过useEffect监听错误变化触发处理逻辑,更符合React的声明式开发范式:
首先改造业务Hook:
const useRequestSomething() { const [data, setData] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); // 新增错误状态 const isRequesting = useRef(false); const requestSomething = async (someParam, onSuccess = undefined) => { if (isRequesting.current) return; isRequesting.current = true; setIsLoading(true); setError(null); // 发起请求前重置错误状态 try { const res = await api.requestSomething(someParam); setData(res); onSuccess?.(); } catch(err) { setError(err); } setIsLoading(false); isRequesting.current = false; } return { data, isLoading, error, requestSomething } }
组件内使用:
function MyComponent() { const toast = useToast(); const { t } = useTranslation(); const { data, isLoading, requestSomething, error } = useRequestSomething(); // 监听错误变化触发提示 useEffect(() => { if (error) { toast.display(t(error), { type: "error", duration: 500 }) } }, [error, t, toast]) const handleOnPress = () => { requestSomething("x") } // ... 剩余JSX逻辑 }
方案3:请求拦截器层统一处理
如果你的绝大多数请求错误都需要弹toast提示,也可以直接在请求库(如Axios)的响应拦截器中统一做错误处理,仅将需要特殊处理的错误抛出给业务层即可,进一步减少重复代码。
内容的提问来源于stack exchange,提问作者Victor Molina
相关产品推荐
相关产品推荐

