当前位置: 首页 > 知识库问答 >
问题:

组件和渲染之间的反应路由器差异

钱哲茂
2023-03-14

我真的不知道react router中render和component prop in Route之间的区别,在文档中它说render不创建新元素,但component创建新元素,我试图返回历史,但我发现在使用render in Route时调用componentWillMount,“如果为组件属性提供内联函数,则在每次渲染时都会创建一个新组件。这将导致现有组件卸载和新组件装载,而不仅仅是更新现有组件。”

共有3个答案

爱刚捷
2023-03-14

大多数概念已由其他答案解释,让我通过以下方式进行整理:

首先,我们有源代码:

if (component)
  return match ? React.createElement(component, props) : null

if (render)
  return match ? render(props) : null
<Route path="/create" component={CreatePage} />

React.createElement(CreatePage, props)被调用,因为React.createElement(组件,props)来自源代码。实例化将导致重新挂载。

<Route path="/create" render={CreatePage} />

<代码>反应。createElement(CreatePage,props)在传递到render prop之前被调用,然后由源代码中的render(props)调用。没有实例化,没有重新装载。

<Route path="/create" component={ () => <CreatePage /> } />

<代码>反应。createElement(CreatePage,props)可以调用两次。第一个用于jsx解析(匿名函数),第一个用于从匿名函数返回CreatePage的实例,第二个用于从源代码返回。那么为什么不在组件道具中执行此操作呢

oligofren指出的错误:

解析JSX不会调用它。它最终只会创建函数表达式。您不想做#3的原因是您每次都创建一个新的匿名类型,从而导致重新挂载dom。

<Route path="/create" render={ () => <CreatePage /> } />

每次路由到路径=/创建时都有一个实例化(jsx解析)。感觉像案例1吗?

根据这四种情况,如果我们想将prop传递给Component,我们需要使用case#4来防止重新挂载。

<Route path="/abc" render={()=><TestWidget num="2" someProp={100}/>}/>

这离主题有点远,所以我把正式讨论留给进一步阅读。

姜玉泽
2023-03-14

所以我对文档的这一部分也感到困惑,但我终于明白了。

理解这一点的关键是“为组件属性提供内联函数”的语句

我们都知道,路由组件将在位置更改时重新渲染,react将比较新旧虚拟DOM树,得到一些差异结果并应用于真实DOM。

ReactElement会尝试重用DOM节点,除非更改了新ReactElement的类型或key prop。

所以

// 1.
const componentA = React.createElement(App, props)
const componentB = React.createElement(App, props)
console.log(componentA.type === componentB.type)             // true

// 2.
const componentA = React.createElement(() => <App />, props)
const componentB = React.createElement(() => <App />, props)
console.log(componentA.type === componentB.type)             // false

通过方式1创建的所有ReactElements都具有相同的类型(应用程序组件),但如果它们都是通过方式2创建的,则它们的类型不同。

为什么?

因为在调用父组件(包含路由组件的组件)的呈现方法时,总是会以方式2创建一个新的匿名函数,所以

() => <App />

因此,在React看来,有不同类型的元素,应该用unmount old来处理

但是为什么渲染属性会避免卸载和装载行为呢?这也是一个匿名函数!?

这里我想引用@Rishat Muhametshin发布的代码,这是Route组件渲染方法的核心部分:

if (component)
  // We already know the differences:
  // React.createElement(component)
  // React.createElement(() => <component/>)
  return match ? React.createElement(component, props) : null

if (render)
  return match ? render(props) : null

render prop是一个调用时返回ReactElement的函数,返回的元素是什么类型的?

<Route render={() => <AppComponent />}></Route>

这是AppComponent,不是匿名函数包装器!因为在jsx编译之后:

render = () => React.createElement(AppComponent)
render() = React.createElement(AppComponent)

React.createElement(render) =
  React.createElement(() => React.createElement(AppComponent))

React.createElement(render()) =
  React.createElement(React.createElement(AppComponent))

因此,当您使用渲染而不是组件prop时,渲染prop函数返回的元素类型不会在每次渲染时更改,即使在每个父级上总是创建一个新的匿名函数实例lement.render()

在我看来,您可以通过为匿名函数命名来实现渲染prop对组件prop所做的相同行为:

// Put this line outside render method.
const CreateAppComponent = () => <AppComponent />

// Inside render method
render(){
  return <Route component={CreateAppComponent}/>
}

因此得出的结论是,如果您直接使用component={AppComponent},那么component和render prop之间的性能没有差别,如果您想为AppComponent分配一些prop,请使用render={()=

程举
2023-03-14

源代码说明了区别:

if (component)
  return match ? React.createElement(component, props) : null

if (render)
  return match ? render(props) : null

当您使用组件prop时,该组件会在每次调用Route#渲染时实例化。这意味着,对于您传递给Route的组件prop的组件,构造函数、组件WillMount组件ddMount将在每次渲染路由时执行。

例如,如果你有

<Route path="/:locale/store" component={Store} />

用户导航到/en/store,然后转到其他位置,然后导航回/en/store,存储组件将被装载,然后卸载,然后再次装载。这类似于

<Route path="/:locale/store">
  <Store />
</Route>

与此相比,如果使用渲染属性,则会在每个渲染路径上对组件进行评估。记住,每个组件都是一个函数?此函数将按原样执行,没有任何生命周期方法。所以当你拥有它的时候

<Route path="/:locale/store" render={Store} />

你可以把它想象成

<Route path="/:locale/store">
  {Store()}
</Route>

它节省了您的运行时,因为没有运行生命周期方法,但如果存储组件有一些装载后生命周期方法,如shouldComponentUpdate,它也有一个缺点,这可能会提高性能。

媒体上有一篇关于这个性能黑客的好帖子,请看看。它写得很好,也适用于React 16。

 类似资料:
  • I my app.js我已将路线定义为: 在我的中,我有一个链接: 但问题是,当我在aboue path中设置prop'确切={true}时,找不到这个路径 当我没有在上面的路径中设置exact={true}时,在同一页面上呈现路径组件及其下方的路径组件

  • 有人能解释一下 和 我不知道确切的意思。

  • 所以就像标题所说的,我的应用程序的主页因为某种原因渲染了两次,我不知道为什么。从我的浏览器路由器,我最初调用一个JS文件,从那里我调用我的HomePage组件和React路由器,但然后我的页面渲染两次,我不知道为什么。 我的浏览器路由器(index.js): 然后pp.js被称为: 然后我的主页组件(index.jsx): 和路线。js: 但是我的页面是这样渲染的: 我真的很困惑,所以任何建议都会

  • 问题: 有异步路由,从中获取参数并返回(组件)。问题是当我从一个到另一个(只是相同的路由,但不同。参数)我的路由器卸载并重新渲染组件。但它应该只传递新的道具,不要触及我的组件生命周期。怎么解决呢?我做错了什么? 代码: 路由器 组件将装入电影组件中 更新:好的,做了一些实验。 替换

  • 嗨,我不确定这是一个期望的行为还是一个bug。 这是一个空的create react应用程序示例,带有 版本: 反应:^16.13.1, react-dom:^16.13.1, react-router-dom:^5.2.0, 反应脚本:3.4.1 部件: /-对于主部件 /触点-用于触点组件 这里提供小提琴 多次单击“主页”链接会显示一条

  • 我是一个新的反应和反应。我已经花了几个小时了,我只是走到了死胡同。 我正在使用CreateReact应用程序和用于css的bulma。我的依赖项: }, 我查看了stackoverflow的所有相关问题,创建了react应用程序文档,并在他们的回购协议中搜索了他们的开放问题部分,谷歌搜索了所有可能的关键字。我不知所措。 我的路由器只会呈现一个路由(Homeroute)。 如何让它显示/创建路线?