React-router-Dom useNavigate引发地图应用卡片重复渲染问题求助
解决地图移动时侧边栏卡片重复渲染的问题
你的问题核心在于地图移动触发URL搜索参数变化,进而导致组件树重渲染,侧边栏的Card组件也跟着不必要地重复渲染。结合你的代码,我整理了几个针对性的优化方案:
1. 用React.memo包裹Card组件
React.memo会对组件的props做浅比较,只有当props真正发生变化时才会重新渲染组件。你的Card组件接收的title、img、color等props在地图移动时并没有变化,所以这是最直接的优化手段。
修改你的Card.js:
import { memo } from 'react'; // 引入memo import useNavigateSearch from "../../../hooks/useNavigateSearch"; const Card = ({title, img, color, route, id}) => { const navigate = useNavigateSearch(); console.log('render') const handleClick = (route, id) => { navigate(`${route}/${id}`, {map: '2d'}) } return ( <div className="w-24 h-20 mt-1 flex flex-col justify-center items-center cursor-pointer" onClick={()=> handleClick(route, id)}> <div className={`w-12 h-12 ${color} rounded-full flex justify-center items-center`}> <img src={img} className="w-8 h-8 brightness-0 invert"/> </div> <div className="text-sm"> {title} </div> </div> ) } export default memo(Card); // 用memo包裹后导出
2. 优化useNavigateSearch的返回函数,保持引用稳定
当前你的useNavigateSearch每次调用都会返回一个新的箭头函数,这会导致Card组件每次渲染时拿到的navigate都是新引用。我们可以用useCallback让这个函数引用稳定下来:
修改useNavigateSearch.js:
import {createSearchParams, useNavigate} from "react-router-dom"; import { useCallback } from 'react'; // 引入useCallback const useNavigateSearch = () => { const navigate = useNavigate(); // 用useCallback包裹,确保函数引用稳定 return useCallback((pathname, params) => { navigate({ pathname, search: `?${createSearchParams(params)}` }); }, [navigate]); // 依赖仅为稳定的navigate函数 }; export default useNavigateSearch;
3. 用useCallback包裹Card中的handleClick函数
为了彻底避免因函数引用变化导致的潜在重渲染,我们可以用useCallback包裹Card里的点击事件处理函数:
修改Card.js中的handleClick部分:
import { memo, useCallback } from 'react'; import useNavigateSearch from "../../../hooks/useNavigateSearch"; const Card = ({title, img, color, route, id}) => { const navigate = useNavigateSearch(); console.log('render') // 用useCallback包裹,依赖为稳定的navigate、route、id const handleClick = useCallback(() => { navigate(`${route}/${id}`, {map: '2d'}) }, [navigate, route, id]); return ( <div className="w-24 h-20 mt-1 flex flex-col justify-center items-center cursor-pointer" onClick={handleClick}> {/* 直接绑定函数,避免创建新箭头函数 */} <div className={`w-12 h-12 ${color} rounded-full flex justify-center items-center`}> <img src={img} className="w-8 h-8 brightness-0 invert"/> </div> <div className="text-sm"> {title} </div> </div> ) } export default memo(Card);
完成以上修改后,只有当Card的props(route、id等)或稳定化后的navigate函数发生变化时,组件才会重新渲染,地图移动时的URL参数变化就不会再触发不必要的渲染了。
额外检查点
- 确保父组件传递给Card的
img、color等props不是每次渲染都生成新引用(比如动态生成的对象),如果是这种情况,需要用useMemo对这些props做稳定化处理。 - 确认Redux状态更新时,没有意外更新侧边栏相关的状态(根据你的描述,侧边栏状态由URL控制,这部分应该没问题)。
内容的提问来源于stack exchange,提问作者Selahattin ŞİŞMAN
相关产品推荐
相关产品推荐

