如何将组件状态导出为自定义Hook并跨组件无Props使用
问题解决:自定义Hook共享组件状态(无需Props/Redux)
问题背景
需求是通过自定义Hook在OtherComp中访问MyComp内部的请求数据,无需Props传递,同时避免父组件状态导致的全局重渲染。当前MyComp能正常渲染请求数据,但OtherComp调用useMyHook时返回空数组,因为两次Hook调用的状态是独立实例。
问题根源
原useMyHook中使用的useState是组件级独立状态,每次调用Hook都会创建全新的状态实例,所以MyComp和OtherComp的data完全隔离,无法共享。
解决方案:全局状态+订阅模式
通过实现一个全局状态容器,配合订阅机制,让所有调用useMyHook的组件共享同一份状态,同时只在状态变化时更新订阅的组件,避免全局重渲染。
1. 改造自定义Hook useMyHook.ts
import { useState, useEffect } from 'react'; // 全局单例状态存储真实数据 let globalData: any[] = []; // 存储订阅组件的状态更新函数 const subscribers: Set<(data: any[]) => void> = new Set(); // 更新全局状态并通知所有订阅者 const setGlobalData = (newData: any[]) => { globalData = newData; // 传递副本避免引用类型导致的意外更新 subscribers.forEach(update => update([...globalData])); }; export const useMyHook = () => { // 组件本地状态,用于触发组件重渲染 const [localData, setLocalData] = useState([...globalData]); useEffect(() => { // 订阅全局状态变化 const updateLocalState = (newData: any[]) => setLocalData(newData); subscribers.add(updateLocalState); // 组件卸载时取消订阅,防止内存泄漏 return () => subscribers.delete(updateLocalState); }, []); const addItem = (item: unknown) => { setGlobalData([...globalData, item]); }; return { data: localData, setData: setGlobalData, addItem, }; }; export default useMyHook;
2. 保持MyComp.tsx逻辑不变
import { useEffect } from 'react'; import useMyHook from './useMyHook'; const MyComp = () => { const { data, setData } = useMyHook(); const req = async () => { // 模拟异步请求 const { values } = await new Promise(resolve => { setTimeout(() => resolve({ values: [{ name: 'Example1' }, { name: 'Example2' }] }), 1000); }); setData(values); }; useEffect(() => { req() }, []); return ( <div> {data.map((item, index) => <p key={index}>{item.name}</p>)} </div> ); }; export { useMyHook }; export default MyComp;
3. OtherComp使用方式保持不变
import MyComp, { useMyHook } from '../../../components/MyComp'; const OtherComp = () => { const { data } = useMyHook(); return ( <div> <button type="button" onClick={() => console.log(data)}> click test </button> <MyComp /> </div> ); }; export default OtherComp;
效果说明
MyComp请求完成后更新全局状态,所有订阅了useMyHook的组件(包括OtherComp)会同步拿到最新数据- 只有订阅的组件会在状态变化时重渲染,避免全局不必要的更新
- 无需Props传递,也不依赖Redux等外部状态管理库
内容的提问来源于stack exchange,提问作者Dhenyson Jhean
相关产品推荐
相关产品推荐

