React自定义Hook如何向返回的回调函数注入参数
回调参数传递的本质
你在<input />上写的onChange回调能拿到event参数,根本没有什么特殊魔法:不管是浏览器原生事件系统还是React的合成事件系统,都是在事件触发的时机,主动调用你传入的回调函数,同时把提前构造好的事件对象作为实参传进去而已。
给个最直白的简化模拟:
// 模拟input事件的处理逻辑 function initInputChange(dom, userOnChange) { dom.addEventListener('input', (e) => { // 内部构造好合成事件对象 const syntheticEvent = wrapNativeEvent(e); // 调用用户传的回调,把事件对象传进去——这就是你拿到的event参数 userOnChange(syntheticEvent); }) }
说白了参数注入的核心逻辑就是:谁调用回调,谁负责传参。你要在自定义Hook里实现一样的效果,完全遵循这个逻辑就行。
自定义Hook回调注入的实现方式
实现步骤非常直接:
- Hook接收用户传入的配置对象,从中读取用户注册的各类回调(比如
onSuccess、onError) - Hook内部执行自身的业务逻辑,当走到需要触发回调的节点时,主动调用对应回调,把要注入的参数(比如接口返回值、错误对象等)作为实参传入即可。
对应你举的useHello例子,最简实现代码如下:
import { useCallback } from 'react'; function useHello(config = {}) { // 解构用户传入的参数和回调,给回调加默认空函数避免未传时报错 const { arg1, onSuccess = () => {}, onError = () => {} } = config; // Hook内部的核心执行方法 const run = useCallback(async () => { try { // 内部业务逻辑,比如根据arg1发请求 const response = await fetch(`/api/hello?name=${encodeURIComponent(arg1)}`).then(res => res.json()); // 核心:触发成功回调,把response作为参数注入 onSuccess(response); return response; } catch (err) { // 错误场景同理,注入错误对象 onError(err); } }, [arg1, onSuccess, onError]); return { run }; }
使用时的效果和你预期完全一致:
const { run: hello } = useHello({ arg1: 'person name', onSuccess: (response) => { // 这里直接拿到Hook内部注入的response参数 console.log('接口返回结果', response); } }); // 触发执行,成功后会自动执行onSuccess hello();
优化点:避免回调引用变化导致的重渲染
上面的基础写法有个小问题:如果用户传入的回调没有用useCallback包裹,每次组件渲染都会生成新的函数引用,会导致Hook内部的useCallback依赖频繁变化,可能触发不必要的重渲染。
可以用useRef存储最新的回调引用,不需要把回调加入依赖项,优化后代码:
import { useCallback, useRef } from 'react'; function useHello(config = {}) { // 用ref始终存储最新的配置和回调 const configRef = useRef(config); configRef.current = config; const { arg1 } = config; const run = useCallback(async () => { const { onSuccess = () => {}, onError = () => {} } = configRef.current; try { const response = await fetch(`/api/hello?name=${encodeURIComponent(arg1)}`).then(res => res.json()); onSuccess(response); return response; } catch (err) { onError(err); } }, [arg1]); // 依赖项只保留真正影响逻辑的arg1即可 return { run }; }
这个写法和React官方推荐的回调存储方式一致,不会有闭包拿旧值的问题,也能避免不必要的函数重建。
内容的提问来源于stack exchange,提问作者programmerdev
相关产品推荐
相关产品推荐

