React中使用useRedirect自定义钩子出现快速重渲染错误
解决React自定义useRedirect钩子导致重复渲染与跳转循环的问题
问题分析
你的代码存在两个核心问题,直接引发了重复渲染和错误:
convoPartner每次渲染都重新生成:组件每次渲染时都会执行JSON.parse(localStorage.getItem("convoPartner")),生成全新的对象实例,哪怕localStorage内容未变化。validator函数和path每次都是新引用:箭头函数() => !!convoPartner在每次渲染时都会创建新的函数引用;path虽为字符串,但依赖convoPartner._id,而convoPartner每次都是新对象,导致path也会被重新生成(即使字符串内容相同)。
这两个问题会让useRedirect里的useEffect依赖项每次渲染都发生变化,进而触发useEffect重复执行,调用navigate后又会触发组件重新渲染,形成循环。
修复方案
1. 缓存convoPartner,避免重复解析
用useState和useEffect在组件挂载时读取一次localStorage,后续仅在需要时更新,避免每次渲染都重新解析:
// MainLayout.js import { useState, useEffect, useCallback, useMemo } from 'react'; import { useRedirect } from './useRedirect'; const MainLayout = () => { const [convoPartner, setConvoPartner] = useState(null); // 组件挂载时读取localStorage useEffect(() => { const savedPartner = localStorage.getItem("convoPartner"); if (savedPartner) { setConvoPartner(JSON.parse(savedPartner)); } }, []); // 缓存validator函数,仅在convoPartner变化时更新 const validator = useCallback(() => !!convoPartner, [convoPartner]); // 缓存跳转路径,仅在convoPartner的_id变化时更新 const redirectPath = useMemo(() => { return convoPartner ? `/c/${convoPartner._id}` : ''; }, [convoPartner?._id]); useRedirect(redirectPath, validator); // ... 其他组件代码 };
2. 优化useRedirect钩子,避免重复跳转
在钩子中加入当前路径判断,只有当当前路径不等于目标路径时才执行跳转,进一步防止循环:
// useRedirect.js import { useEffect } from 'react'; import { useNavigate, useLocation } from 'react-router-dom'; export const useRedirect = (path, validator) => { const navigate = useNavigate(); const location = useLocation(); useEffect(() => { // 验证通过且当前路径不是目标路径时才跳转 if (validator() && path && location.pathname !== path) { navigate(path); } }, [path, validator, navigate, location.pathname]); }
为什么之前的useMemo/useCallback没生效?
你之前的尝试未起作用,大概率是因为没有先解决convoPartner每次渲染都重新生成的问题——如果convoPartner每次都是新对象,依赖它的useMemo/useCallback也会跟着每次更新,无法起到缓存作用。先把convoPartner用state缓存,才能让后续的缓存函数和路径真正生效。
内容的提问来源于stack exchange,提问作者user22362540
相关产品推荐
相关产品推荐

