scu*_*lly 40 reactjs react-router
我真的没有得到反应路由器中的路由中渲染和组件道具之间的区别,在文档中它表示渲染不会创建新元素但组件确实如此,我试图回溯历史但我发现当我调用componentWillMount时在Route中使用render,它们是什么意思"如果你为组件属性提供内联函数,你将在每次渲染时创建一个新组件.这会导致现有组件卸载和新组件安装,而不仅仅是更新现有组件".
ris*_*hat 53
源代码说明了区别:
if (component)
return match ? React.createElement(component, props) : null
if (render)
return match ? render(props) : null
Run Code Online (Sandbox Code Playgroud)
当你使用componentprop时,每次调用都会实例化组件Route#render.这意味着,对于传递给componentRoute,构造函数的prop的组件componentWillMount,并且componentDidMount每次呈现路径时都会执行.
例如,如果你有
<Route path="/:locale/store" component={Store} />
Run Code Online (Sandbox Code Playgroud)
并且用户导航到/ en/store,然后转到其他地方,然后导航回/ en/store,Store组件将被挂载,然后卸载,然后再次挂载.它类似于做
<Route path="/:locale/store">
<Store />
</Route>
Run Code Online (Sandbox Code Playgroud)
与此相比,如果使用renderprop,则会对每个组件进行评估Route#render.还记得每个组件都是一个功能吗?此函数将按原样执行,无需任何生命周期方法.所以当你拥有它时
<Route path="/:locale/store" render={Store} />
Run Code Online (Sandbox Code Playgroud)
你可以把它想象成
<Route path="/:locale/store">
{Store()}
</Route>
Run Code Online (Sandbox Code Playgroud)
它节省了运行时,因为没有运行生命周期方法,但它也有一个缺点,例如,Store组件有一些post-mount生命周期方法,如shouldComponentUpdate,也可以提高性能.
关于这个性能黑客的媒体有一篇很好的帖子,请看一下.它编写得非常好,也适用于React 16.
ilo*_*zcd 28
所以我对这部分文档感到困惑,但我终于明白了.
理解这一点的关键是声明" 为组件道具提供内联函数 "
我们都知道Route组件将在位置发生变化时重新渲染,并且react将比较新旧虚拟DOM树,得到一些diff结果并应用于真实DOM.
除非更改了新ReactElement 的类型或关键支柱,否则react会尝试重用DOM节点.
所以
// 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
Run Code Online (Sandbox Code Playgroud)
通过方式1创建的所有ReactElements都具有相同的类型(App组件),但如果它们都是通过方式2创建的,则它们不具有相同的类型.
为什么?
因为当父组件(包含Route组件的组件)render方法被调用时,总是会以2的方式创建一个新的匿名函数,所以新旧ReactElement的类型是匿名函数的两个不同实例
() => <App />
Run Code Online (Sandbox Code Playgroud)
因此,在React的观点中,有不同的类型元素,应该使用unmount old> mount new操作来处理,这意味着每次状态或对旧组件所做的更改在每次重新呈现父组件时都会丢失.
但为什么渲染道具避免了卸载和挂载行为?这也是一个匿名函数!?
在这里,我想引用@Rishat Muhametshin发布的代码,这是Route组件的render方法的核心部分:
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
Run Code Online (Sandbox Code Playgroud)
render prop是一个在调用时返回ReactElement的函数,返回元素的类型是什么?
<Route render={() => <AppComponent />}></Route>
Run Code Online (Sandbox Code Playgroud)
它是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))
Run Code Online (Sandbox Code Playgroud)
所以当你使用render而不是组件prop时,渲染prop函数返回的元素类型在每次渲染时都不会改变,即使总是在每个parentElement.render()上创建一个新的匿名函数实例
在我看来,你可以通过为匿名函数命名来归档与prop组件prop相同的行为:
// Put this line outside render method.
const CreateAppComponent = () => <AppComponent />
// Inside render method
render(){
return <Route component={CreateAppComponent}/>
}
Run Code Online (Sandbox Code Playgroud)
所以结论是,如果你直接使用component = {AppComponent},那么组件和渲染道具之间的性能不同,如果你想为AppComponent分配一些道具,请使用
render={() => <AppComponent {...props}/> }而不是component={() => <AppComponent {...props}/> }
Tok*_*yet 10
其他答案已经解释了大多数概念,下面让我对其进行梳理:
首先,我们有源代码:
if (component)
return match ? React.createElement(component, props) : null
if (render)
return match ? render(props) : null
Run Code Online (Sandbox Code Playgroud)
<Route path="/create" component={CreatePage} />
Run Code Online (Sandbox Code Playgroud)
React.createElement(CreatePage, props)由于React.createElement(component, props)源代码而被调用。实例化将导致重新安装。
<Route path="/create" render={CreatePage} />
Run Code Online (Sandbox Code Playgroud)
React.createElement(CreatePage, props) 在传递到渲染道具之前被调用,然后render(props)从源代码调用。没有实例,没有重新安装。
<Route path="/create" component={ () => <CreatePage /> } />
Run Code Online (Sandbox Code Playgroud)
React.createElement(CreatePage, props)被叫两次。首先用于jsx解析(匿名函数),首先用于CreatePage从匿名函数返回的实例,其次用于源代码。那么,为什么不在组件属性中执行此操作呢?
oligofren指出错误:
解析JSX不会调用它。最终只是创建函数表达式。您不想执行#3的原因是您每次都创建一个新的匿名类型,从而导致dom的重新安装。
<Route path="/create" render={ () => <CreatePage /> } />
Run Code Online (Sandbox Code Playgroud)
每次路由到时都有一个实例化(jsx解析)path=/create。感觉像情况#1吗?
根据这四种情况,如果我们想将prop传递给Component,则需要使用案例#4来防止重新安装。
<Route path="/abc" render={()=><TestWidget num="2" someProp={100}/>}/>
Run Code Online (Sandbox Code Playgroud)
这离主题有点远,所以我将正式讨论留给进一步阅读。
| 归档时间: |
|
| 查看次数: |
14197 次 |
| 最近记录: |