如何条件性运行React自定义Hook?解决误跳转编辑页问题
解决自定义Hook条件跳转问题
问题根源
你当前的useDuplicateItem在组件渲染时就直接调用了useRedirectEditPage,导致这个跳转监听Hook只要组件存在就会生效。删除操作会更新saveResponses状态,触发useRedirectEditPage里的useEffect,进而执行跳转逻辑,这就是删除时也会跳转到编辑页的原因。
解决方案
下面提供两种可行的解决思路,你可以根据项目需求选择:
方案一:给跳转Hook添加启用开关
修改useRedirectEditPage,增加一个enabled参数控制监听逻辑是否生效:
export default function useRedirectEditPage(slug: string, enabled: boolean = true) { const { saveResponses, setSaveResponses, setHeaderStates } = useAdminContext(); const router = useRouter(); useEffect(() => { // 未启用时直接退出,不执行监听逻辑 if (!enabled) return; const statusCodes: number[] = []; let id; saveResponses.forEach((value) => { statusCodes.push(value?.status); id = value?.id; }); if (statusCodes.length && id) { if (statusCodes.includes(404)) { setHeaderStates((prev) => ({ ...prev, canBeSaved: false, })); } else { router.push(`/admin/${slug}/edit/${id}`); setSaveResponses(new Map()); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [saveResponses, router, setSaveResponses, enabled]); }
接着修改useDuplicateItem,用状态控制跳转Hook的启用,只有执行复制操作时才开启监听:
export default function useDuplicateItem(url: string) { const { sendRequest: duplicate } = useHttpRequest(); const [isDuplicating, setIsDuplicating] = useState(false); const duplicateItem = useCallback( (data) => { setIsDuplicating(true); duplicate([ { url: `/api/server/${url}`, method: 'POST', headers: { 'Content-Type': 'application/json', }, data, }, ]); }, [duplicate, url] ); // 仅在复制操作执行后启用跳转监听 useRedirectEditPage(url, isDuplicating); return duplicateItem; }
方案二:将跳转逻辑绑定到复制请求回调
如果useHttpRequest的sendRequest返回Promise,可以直接在复制请求完成后处理跳转,无需单独的监听Hook:
export default function useDuplicateItem(url: string) { const { sendRequest: duplicate } = useHttpRequest(); const { saveResponses, setSaveResponses, setHeaderStates } = useAdminContext(); const router = useRouter(); const duplicateItem = useCallback( async (data) => { // 执行复制请求 await duplicate([ { url: `/api/server/${url}`, method: 'POST', headers: { 'Content-Type': 'application/json', }, data, }, ]); // 请求完成后处理跳转逻辑 const statusCodes: number[] = []; let id; saveResponses.forEach((value) => { statusCodes.push(value?.status); id = value?.id; }); if (statusCodes.length && id) { if (statusCodes.includes(404)) { setHeaderStates((prev) => ({ ...prev, canBeSaved: false, })); } else { router.push(`/admin/${url}/edit/${id}`); setSaveResponses(new Map()); } } }, [duplicate, url, saveResponses, router, setSaveResponses, setHeaderStates] ); return duplicateItem; }
方案对比
- 方案一保留了
useRedirectEditPage的复用性,适合需要在多个场景复用跳转逻辑的情况。 - 方案二更直接,把跳转逻辑和复制操作强绑定,避免了全局监听带来的意外触发,适合只在复制场景使用跳转的情况。
内容的提问来源于stack exchange,提问作者Ozan
相关产品推荐
相关产品推荐

