React router 中 Route的子组件也就是component属性指定的组件总是重复触发render

const App = () => {
    return (
       <Layout>
           <Suspense fallback={<RoutePageLoading height="calc(100vh - 65px)" />}>
                <Switch>
                    <Route path="/xxx" component={lazy(() => import('src/xxx/xxx'))} />
                </Switch>
           </Suspense>
       </Layout>
    )
}

像上面这段代码,其中Layout组件是一个类似antd里的layout,由Header、Sider、Content组成,Layout的child放在Content下,也就是每个路由。
其中父组件Layout里有个Redux控制的store,这个store只在Layout里修改和使用,子组件根本不会修改也没有读取,也不会触发路由的修改,但是现在每次在Layout里修改这个store就会触发Route的component的render。
问题是如何避免Route组件的render?
我使用memo包裹Route的component,好像没发生作用,因为我在memo的第二个参数,比较函数里log一些东西,在控制台根本就没触发。。。

阅读 3.2k
1 个回答

通过对组件更新的情况可以排查到。是route给子组件传递的porops发生了变更 导致页面发生了变化。
image.png
一般情况下这种render是需要的,因为路由变化了 子组件应该要或得到对应参数并且根据情况处理。如果真的就是不想render呢?
下面的例子经过测试 都能够拒绝第二次的render。也可以根据情况在useMemo中放入真正需要的依赖进行对应的render。

const Com = lazy(() => import('./App2'))
const Com2 = () => {
    const instance = useMemo(() => {
        return <Com/>
    }, [])
    return instance
}
export default function Home(props) {
    const [a, setA] = useState('')
    useEffect(() => {
        setTimeout(() => {
            setA(233)
        }, 500)
    }, [])
    const Render = useMemo(() => {
        return <Com/>
    }, [])
    return (
        <Router>
            <Switch>
                <Suspense fallback={'233'}>
                    {/* 1. route props 因为提供的是一个组件 需要在组件内memo */}
                    <Route exact path="/" component={Com2}>
                    </Route>
                     {/*2. route props 无法注入 直接传入一个memo后的组件即可*/}
                    <Route exact path="/" render={() => Render}>
                    </Route>
                    <Route exact path="/">
                        {Render}
                    </Route>
                </Suspense>
            </Switch>
        </Router>
    )
}

-------下面答案虽然说的是正确的,但是对本题没有帮助
react-router component不要使用匿名函数 因为component渲染的时候会调用react.createElement,每次传入的函数引用都不同,会导致生成的组件type不相同,会重复挂载和卸载.

下列为对照组。代码分别更新了一次全局状态 可以看到使用匿名函数的component渲染了两次,使用chilren渲染了一次。
注意Com不要再函数内赋值。不依赖状态,直接放在文件最外层就好了。
image.png

增加两个小tip

  1. 渲染优先级 children>component>render
  2. children无论是否匹配[switch]都显示
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题