如何在React useMemo钩子函数内部正确使用其他React钩子?
问题根因
React Hook 有强制调用规则:所有Hook必须在React函数组件或自定义Hook的最顶层作用域调用,不能嵌套在useMemo、useEffect、条件判断、循环等代码块的回调中执行。你把useTextStyle(自定义Hook)放到useMemo回调里的写法违反了这条规则,因此触发警告。
最优实现方案(符合「仅遍历一次主题数据」的优化需求)
推荐将样式计算逻辑抽离为纯函数,统一获取依赖后一次计算所有样式,避免重复调用Hook和重复遍历主题数据:
第一步:调整计算逻辑为纯函数
// 原computeTextStyles调整为接收theme、colorMode作为入参,无内部Hook调用 function computeTextStyles(component: string, theme: Theme, colorMode: string): TextStyle { // 保留原有样式计算逻辑,直接使用传入的参数即可 } // 新增纯函数:一次遍历主题数据,生成所有需要的文本样式 function generateAllTextStyles(theme: Theme, colorMode: string) { return { header1: computeTextStyles('Heading', theme, colorMode), body: computeTextStyles('Text', theme, colorMode) } }
第二步:重构自定义Hook实现缓存
function useTextStyles() : StyleSheet.NamedStyle<{header1:TextStyle,body:TextStyle}> { // 所有Hook都在顶层调用 const theme = useTheme(); const colorMode = useColorMode(); // 仅当theme或colorMode变化时才重新计算样式,其余时间直接返回缓存结果 return useMemo(() => generateAllTextStyles(theme, colorMode), [theme, colorMode]); } // 如果项目其他地方还需要复用单个样式获取能力,可以保留该Hook做兼容 function useTextStyle(component: string) : TextStyle { const theme = useTheme(); const colorMode = useColorMode(); return useMemo(() => computeTextStyles(component, theme, colorMode), [theme, colorMode, component]); }
轻量兼容方案(不改原有computeTextStyles逻辑)
如果不想调整现有computeTextStyles和useTextStyle的实现,也可以调整Hook调用顺序,将所有Hook调用放到顶层后再做缓存:
function useTextStyles() : StyleSheet.NamedStyle<{header1:TextStyle,body:TextStyle}> { // 所有自定义Hook都在顶层调用 const header1 = useTextStyle('Heading'); const body = useTextStyle('Text'); // 仅当样式本身变化时才更新返回对象的引用 return useMemo(() => ({ header1, body }), [header1, body]); }
该方案的不足是
computeTextStyles会执行两次,如果你每次计算都会全量遍历主题数据,性能不如第一种方案。
内容的提问来源于stack exchange,提问作者Archimedes Trajano
相关产品推荐
相关产品推荐

