I really don't get the difference between render and component prop in Route in react router, in docs it says that render doesn't create new element but component does, I tried to go back with history but I found componentWillMount is called when I use render in Route, what do they mean by "if you provide an inline function to the component attribute, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component."
5 Answers
The source code tells the difference:
if (component)
return match ? React.createElement(component, props) : null
if (render)
return match ? render(props) : null
When you use component
prop, the component is instantiated per every call of Route#render
. It means that, for your component that you pass to component
prop of Route, constructor, componentWillMount
, and componentDidMount
will be executed every time the route is rendered.
For example, if you have
<Route path="/:locale/store" component={Store} />
and the user navigates to /en/store, then goes elsewhere, and then navigates back to /en/store, the Store component will be mounted, then unmounted, and then mounted again. It is similar to doing
<Route path="/:locale/store">
<Store />
</Route>
Compared to that, if you use render
prop, the component is evaluated on every Route#render
. Remember that every component is a function? This function will be executed as is, without any lifecycle methods. So when you have it like
<Route path="/:locale/store" render={Store} />
you can think of it as
<Route path="/:locale/store">
{Store()}
</Route>
It saves you runtime because no lifecycle methods are run, but it also has a downside in case Store component has some post-mount lifecycle methods like shouldComponentUpdate that may increase performance as well.
There was a good post on Medium about this performance hack, please take a look at it. It's written very well and is applicable to React 16, too.

- 8,206
- 4
- 44
- 69
-
In responses to that Medium post, there's [a confirmation that the second option is even faster in react@16](https://medium.com/@trueadm/in-react-16-functional-components-are-quite-a-bit-faster-than-class-components-1afca4931d7c), when compared to stateful components declared as classes. – rishat Jan 08 '18 at 14:55
-
thank you very much, i am just confused cause when i use render i find that componentWillMount is called, and if i change the state at some point and go to another route then go back to my component i found the initial state not the changed one, isn't the docs says " updating the existing component not unmounting it" – scully Jan 08 '18 at 14:58
-
1{Store()} if this component already has lifecycle methods, if i call it like this, how it will be executed without any lifecycle methods – scully Jan 08 '18 at 15:05
-
In fact, `render` prop doesn't behave very well with a component declared as class, as well as any class in ES6 isn't callable. See the [codepen](https://codepen.io/rishatmuhametshin/pen/wppyEg?editors=1010), open the console and try to navigate links. Class component + render prop will throw an error. Function component + component or render prop does not run lifecycle methods (because there aren't any). – rishat Jan 08 '18 at 15:21
-
1so can i say that, i use render with function components and component with class components – scully Jan 08 '18 at 15:57
-
I think you could use `component` prop for everything, to be honest, and only switch to `render` prop when it's really necessary. I'd also recommend using some performance analytics tool like Lighthouse to detect which one works best in usage patterns close to the real ones (but please avoid sandboxed perf metrics, these usually fail to detect real bottlenecks). – rishat Jan 08 '18 at 20:49
-
so regardless of what method you are using `render` or `component`, if you are rendering a class component it will be mounted and unmounted (calling all lifecycle methods) anyway, do I understand it correctly, @RishatMuhametshin? – margaretkru Jan 08 '18 at 21:10
-
Depends on whether you have nested routes and components in them. If you do, navigation within one Route doesn't unmount component if it's put via `component` prop (aka `React.createElement`), but it does unconditionally re-render it if it's put via `render` prop. – rishat Jan 08 '18 at 21:27
-
See [a forked Codepen](https://codepen.io/rishatmuhametshin/pen/JMMwQL): the message "SmallComponent()" appears per every click on 3rd or 4th link, meaning effectively that the component is being rendered again and again. I actually think React's VirtualDOM engine is smart enough to not update the corresponding part of browser DOM, but not 100% sure. – rishat Jan 08 '18 at 21:31
-
1One caveat is that if you use `
` and you also use react hooks in `Store`, then it's not gonna work because react hooks can only be called in a function component instead of a regular function. – coolgod Jun 12 '21 at 23:19
So I'm confused on this section of docs as well, but I finally figure it out.
The key to understand this is the statement "provide an inline function to the component prop"
We all know that Route component will re-render when the location changed, and react will compare the old and new virtual DOM tree, get some diff result and apply to the real DOM.
And react will try it's best to reuse the DOM node, unless the type or key prop of the new ReactElement is changed.
So
// 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
All ReactElements created by way 1 have the same type(App component), but they don't have the same type if they are all created by way 2.
Why?
Because there is always a new anonymous function created in the way 2 when the parent component's(The component that contains Route component) render method got invoked, so the type of new&old ReactElement is two different instances of the anonymous function
() => <App />
So in React's point of view, there are different types element and should be treat with unmount old > mount new operation, that means every state or changes you made on the old component got loss everytime the parent component re-render.
But why the render prop avoid the unmount and mount behavior? It's an anonymous function too!?
Here I would like to refer the code that @Rishat Muhametshin posted, the core part of Route component's render method:
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 is a function that return a ReactElement when invoked, what's the type of that returned element?
<Route render={() => <AppComponent />}></Route>
It's AppComponent, not the anonymous function wrapper! Because after jsx compiled:
render = () => React.createElement(AppComponent)
render() = React.createElement(AppComponent)
React.createElement(render) =
React.createElement(() => React.createElement(AppComponent))
React.createElement(render()) =
React.createElement(React.createElement(AppComponent))
So when you use render instead of component prop, the type of element that render prop function return will not change on each render, even there always an new anonymous function instance created on each parentElement.render()
On my point of view, you can achieve the same behavior that render prop does with component prop by giving a name to the anonymous function:
// Put this line outside render method.
const CreateAppComponent = () => <AppComponent />
// Inside render method
render(){
return <Route component={CreateAppComponent}/>
}
So the conclusion is, there is not performance different between component and render prop if you are use component={AppComponent} directly, if you want to assign some props to AppComponent, use
render={() => <AppComponent {...props}/> }
instead of component={() => <AppComponent {...props}/> }
Most of concepts have been explained by other answers, Let me sort it out by following:
First of all, we have source code:
if (component)
return match ? React.createElement(component, props) : null
if (render)
return match ? render(props) : null
case #1: component without function
<Route path="/create" component={CreatePage} />
React.createElement(CreatePage, props)
be called because of React.createElement(component, props)
from source code. The instantiation would cause to be remounting.
case #2: render without function
<Route path="/create" render={CreatePage} />
React.createElement(CreatePage, props)
was called before passing into render prop, and then called by render(props)
from source code. No instantiation, no remounting.
case #3: component with function
<Route path="/create" component={ () => <CreatePage /> } />
React.createElement(CreatePage, props)
be called twice. First for jsx parsing(anonymous function), First for returning an instance of CreatePage
from anonymous function, second from source code. So why don't do this in component prop.
Errors point out by oligofren:
Parsing the JSX does not call it. It just ends up creating the function expression. The reason you don't want to do #3 is that you create a new anonymous type each time, causing re-mounting of the dom.
case #4: render with function
<Route path="/create" render={ () => <CreatePage /> } />
There is an instantiation(jsx parsing) each time when routing to path=/create
. Does it feel like case #1?
Conclusion
According to the four cases, If we want to pass prop to Component, we need to use the case #4 to prevent remounting.
<Route path="/abc" render={()=><TestWidget num="2" someProp={100}/>}/>
This is a bit far from the topic, so I leave the official discussion for further reading.

- 4,063
- 2
- 27
- 43
-
"React.createElement(CreatePage, props) be called twice. " No. It won't. Parsing the JSX does not call it. It just ends up creating the function expression. The reason you don't want to do #3 is that you create a new anonymous type each time, causing re-mounting of the dom. – oligofren Aug 28 '19 at 10:30
-
Yeah, you are right, I wrote bad on that time, the important is the `anonymous` creating once when called, and source code, for total *twice*. Thanks for point out with your downvote, Remind me the error. – Tokenyet Aug 28 '19 at 10:37
-
1But your answer still says it's called twice, but the anonymous function is not called when you assign it to the `render` prop. It is created once (when you assign it) and it isn't called until the [`render()` method of `Route`](https://github.com/ReactTraining/react-router/blob/59a4fbc184f3a3cf4c25ee39a7e97f72efed7849/packages/react-router/modules/Route.js#L112-L116) calls it. And only _through that call_ is `React.createElement` called, as it is implicitly part of the anonymous function (after JSX parsing). – oligofren Aug 28 '19 at 11:27
-
Sorry, I misunderstood you. I haven't used React a period of time, maybe I should just reference your comment :) – Tokenyet Aug 28 '19 at 12:44
Even if we don't pass any props to ComponentToRender
, I found some benefits from using render instead of component.
By default <Route \>
pass additional props({ history, location, match }
) to ComponentToRender
when using component. We can access this props via render callback too, but also we can omit it.
Why do we need it? Every render of <Route />'s
parent or any navigation(even if change route to same as before) create new match
object.
So when we pass it to our ComponentToRender
, we will get new props every time, what may cause some performance issues, especially with PureComponent
.

- 41
- 2
Even if we give a name to a function it would create a new reference when this component would be called from any parent component. That new reference would be passed to the component. But we can avoid the creation of new references by using use callback hook.
// Put this line outside render method.
const CreateAppComponent = () => <AppComponent />
// Inside render method
render(){
return <Route component={CreateAppComponent}/>
}

- 19
- 3