Skip to content
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

Closed
1player opened this issue Oct 26, 2016 · 7 comments
Closed

Functional components are re-rendered when props are unchanged. #4037

1player opened this issue Oct 26, 2016 · 7 comments

Comments

@1player
Copy link

1player commented Oct 26, 2016

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).

@defcc defcc added the 2.0 label Oct 27, 2016
@fnlctrl fnlctrl added the bug label Oct 27, 2016
@HerringtonDarkholme
Copy link
Member

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, Date is stateful and not pure. If you need state in functional components, use components.

@1player
Copy link
Author

1player commented Oct 28, 2016

@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. new Date() in this case is just a poor man's debugging tool.

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.

@yyx990803 yyx990803 added improvement and removed bug labels Nov 1, 2016
@yyx990803
Copy link
Member

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.

@essenmitsosse
Copy link

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 functional: true is just removed. While it is said, this makes the component more expensive, it seems like a big saving, when the parent component is rerendered all the time, yet the child component ist completely static.

Would it be recommended to make such a component non-functional?

@web-crab
Copy link

web-crab commented May 24, 2020

You can use memoization

{
  functional: true,
  render: _.memoize(
    (h, ctx) => h('li', { class: 'item' }, ctx.props.name),
    (h, ctx) => JSON.stringify(ctx.props),
  ),
}

@softwareCobbler
Copy link

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?

@SSShooter
Copy link

SSShooter commented Mar 28, 2021

Does it mean functional components can save memory not time, on the contrary, using normal component can save time ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants