能否在useEffect外部调用useSWR?重构代码遇Hook调用错误求解
问题与解决方案
代码示例
export default function myComponent() { async function getResults(myParams ){ const { data, error } = useSWR('/api/blah?myParams=' + myParams ); // 处理其他逻辑... return data; } useEffect(() => { let myParams = someLogicToGetDynamicParams(); myresults= getResults(myParams ); }, [abc]); //... }
报错信息
Unhandled Runtime Error Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM) 2. You might be breaking the Rules of Hooks 3. You might have more than one copy of React in the same app See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
用户疑问
我知道应将useSWR放在useEffect内部,但因逻辑冗长想进行重构,这是否意味着不能将useSWR抽离到单独函数中?
解决方案
不是不能抽离,但不能抽成普通函数,要抽成自定义Hook——这是React允许的Hook复用方式,自定义Hook必须以use开头命名,且只能在组件顶层或其他自定义Hook顶层调用。
重构示例
首先把包含useSWR的逻辑改成自定义Hook:
// 自定义Hook,命名以use开头 function useResults(myParams) { // 仅当myParams存在时发起请求,避免无效调用 const { data, error } = useSWR(myParams ? `/api/blah?myParams=${myParams}` : null); // 处理原有的其他逻辑... return data; }
然后在组件中使用这个自定义Hook:
import { useState, useEffect } from 'react'; export default function myComponent() { // 用状态管理动态参数 const [myParams, setMyParams] = useState(); // 在useEffect里更新参数,而非直接调用Hook useEffect(() => { const params = someLogicToGetDynamicParams(); setMyParams(params); }, [abc]); // 在组件顶层调用自定义Hook,符合React Hooks规则 const myresults = useResults(myParams); //... }
关键说明
- React Hooks规则明确:Hooks只能在函数组件的顶层作用域,或自定义Hook的顶层作用域调用,原代码报错就是因为在普通函数
getResults里调用useSWR,违反了这个规则。 - 自定义Hook是封装Hook逻辑的合法方式,只要遵循
useXXX的命名规范,并在组件顶层调用,就完全合规。 - useSWR本身会根据传入的参数自动触发请求更新,无需在useEffect里手动调用,只需用状态管理动态参数,传给自定义Hook即可实现参数变化时自动发起新请求。
内容的提问来源于stack exchange,提问作者NL3294
相关产品推荐
相关产品推荐

