-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Functional components are re-rendered when props are unchanged. #4037
Comments
I wonder whether it is a bug or an intended feature. According to the doc, functional components are cheap to render. IMHO, the rendering expense of computing reactivity is not required in functional components. It is misleading to think functional components are magically cheaper. They just do less than ordinary components. If functional components are reactive to their props, its cheap nature is not preserved. Users should just keep their function stateless and functional. Yes, a pure function. In the code above, |
@HerringtonDarkholme I respectfully disagree: The use of Date in my example is intended, as that's a good way to check whether the render function has been called when the inputs are unchanged. How do you force a pure function to change its output while keeping the inputs unchanged? Call an impure function. The point is not the use of Date, is that this.render is called on a functional component even when not necessary. This is a bug IMO, because even if functional components are cheap to render (!= free to render), it does not mean we have to render it in all cases, as their very purpose and reason to exist is to give us a simple way of determining whether we can safely skip rendering them. So safely skip rendering them we should when the conditions are appropriate. |
FYI, functional components in Vue are "eager", which means the render function gets called directly during the parent's render cycle without allocating any instance for the child. Because there is no instance associated with them, there's no easy way to perform memoization of previous render results. The desired optimization is not easily obtainable while ensuring correctness in all possible cases. That said, the lack of instance in functional components is a pretty big perf win in most cases, especially for leaf components that are used in large numbers. But it may not be the best choice for complex one-off components, where the presence of an instance allows it to take advantage of static optimization and reactivity boundary. React's functional components are also always re-rendered: facebook/react#5677 I'd be open to suggestions on how this can be achieved, but for now I don't see an actionable path forward. |
I know this issue has been closed for a while, but I just have a small follow-up question, that wouldn't justify its own issue: Like stated a functional component always rerenders, not just when no props have changed, but even when it doesn't have any props at all. This behaviour changes, when the Would it be recommended to make such a component non-functional? |
You can use memoization {
functional: true,
render: _.memoize(
(h, ctx) => h('li', { class: 'item' }, ctx.props.name),
(h, ctx) => JSON.stringify(ctx.props),
),
} |
i see that the render function is run anytime something changes, but is the resulting sub-tree diff'd (and turned into a NOP in most cases) or is the old sub-tree just swapped out with the new one? |
Does it mean functional components can save memory not time, on the contrary, using normal component can save time ? |
Vue.js version
2.0.3
Reproduction Link
https://jsfiddle.net/r4jpy72a/1/
Steps to reproduce
Open the jsfiddle, click the button multiple times.
What is Expected?
Both component not to be re-rendered if the props are not changing.
What is actually happening?
The functional component is re-rendered when the props are unchanged.
The regular component exhibits the expected behaviour.
To optimise and avoid expensive renders in a complex application, I'm moving most of the HTML logic to functional components and expect them not to be re-rendered if the data passed doesn't change.
If this is intended, perhaps the docs should reflect this quirk, but I don't see any reason why we should always call the render function when we can safely assume the resulting HTML to be unchanged (same input == same output).
The text was updated successfully, but these errors were encountered: