React Hooks是否可以生成新Hooks?相关实现规则与场景实践问询
结论
该实现方案完全符合React Hooks规范,是官方推荐的逻辑复用实践。
React的Hook规则仅约束Hook的调用时机,要求必须在React函数组件、或其他自定义Hook的顶层调用,不会限制Hook的定义和生成方式,你要实现的封装属于标准的自定义Hook衍生用法。
实现参考
方案1:单独封装通用自定义Hook
// 通用自定义Hook,接收subscribe实例和回调作为参数 function useSubscriptionEffect<T>( subscribe: SubscriptionManager<T>['subscribe'], fn: (data: T) => void ) { useEffect(() => { return subscribe(fn); }, [subscribe, fn]); }
为了避免effect不必要的重复执行,建议给原useSubscription返回的方法加useCallback包裹保证引用稳定:
export function useSubscription<T = any>(): SubscriptionManager<T> { const subscribersRef = useRef<((data: T) => void)[]>([]); // 用useCallback包裹,保证引用永久稳定 const subscribe = useCallback((fn: (data: T) => void) => { subscribersRef.current.push(fn); return () => { subscribersRef.current = subscribersRef.current.filter( (subscription) => !Object.is(subscription, fn) ); }; }, []); const notify = useCallback((data: T) => { subscribersRef.current.forEach((fn) => fn(data)); }, []); return { subscribe, notify }; }
使用示例:
function DemoComponent() { const { subscribe, notify } = useSubscription<string>(); // 调用自定义Hook,无需重复写useEffect样板代码 useSubscriptionEffect(subscribe, (data) => { console.log('收到通知:', data); }); return <button onClick={() => notify('测试消息')}>发送通知</button>; }
方案2:直接从useSubscription返回预绑定的Hook
如果你希望更易用,也可以直接把封装好的Hook作为useSubscription的返回值:
export function useSubscription<T = any>() { const subscribersRef = useRef<((data: T) => void)[]>([]); const subscribe = useCallback((fn: (data: T) => void) => { subscribersRef.current.push(fn); return () => { subscribersRef.current = subscribersRef.current.filter(s => !Object.is(s, fn)); }; }, []); const notify = useCallback((data: T) => { subscribersRef.current.forEach(fn => fn(data)); }, []); // 预绑定当前subscribe实例的自定义Hook const useSubscriptionEffect = useCallback((fn: (data: T) => void) => { useEffect(() => { return subscribe(fn); }, [fn]); }, [subscribe]); return { subscribe, notify, useSubscriptionEffect }; }
使用示例:
function DemoComponent() { const { notify, useSubscriptionEffect } = useSubscription<string>(); // 直接调用返回的绑定后Hook useSubscriptionEffect((data) => { console.log('收到通知:', data); }); return <button onClick={() => notify('测试消息')}>发送通知</button>; }
两种实现均完全合规,可根据业务需求选择。
内容的提问来源于stack exchange,提问作者Archimedes Trajano
相关产品推荐
相关产品推荐

