yew icon indicating copy to clipboard operation
yew copied to clipboard

How to cache rendered child VNode to avoid calling Child::change on Parent::view?

Open Boscop opened this issue 5 years ago • 0 comments

My app's main bottleneck is the cloning and comparing of props (of one specific component that is instantiated 4 times) that are huge structs and don't change frame to frame. This is being caused by Child::change being called every time Parent is rendered (at 30 fps, for all 4 instantiations). Original code in Parent::view: <Child foo=self.foo.clone()/> I decided to cache the rendered child's VNode and render that, instead of passing the props every time. (I refresh the cached node manually only when foo really changes.) I tried two approaches: 1.:

// ~155% cpu usage but rendering smoothly. also calls Child::change when Parent renders. 
// behavior doesn't differ from non-cached rendering of Child
self.cached_child = html! {
	<Child foo=self.foo.clone()/>
};

2.:

// ~105% cpu usage but stuttering, only refreshing about once every second. doesn't call Child::change when Parent renders
self.cached_child = {
	let mut r = Child::default();
	r.change(child::Props {
		foo: self.foo.clone(),
	});
	r.view()
};

And then both times, in Parent::view I do { self.cached_child.clone() } instead of <Child foo=self.foo.clone()/>:

let dynamic_style = format!(
	"transform-origin: {:.4}% center; transform: translateX({:.4}%) scaleX({:.4});",
	xpos_percent,
	50. - xpos_percent,
	self.zoom
);
html! {
	<div style=dynamic_style>
		{ self.cached_child.clone() }
	</div>
}

So it seems only approach 2 is doing what I want (not calling Child::change every time Parent::view is called, not cloning / comparing its foo prop, which is a huge struct) and thus has lower CPU usage. BUT approach 2 doesn't work: It stutters visually, only updating like once a second. By updating I mean: The dynamic_style is different every time Parent::view is called, because xpos_percent advances every frame (like in a music player), but with approach 2, it behaves as if dynamic_style is only being updated like once a second instead of at 30 fps, EVEN THOUGH Parent::view is being called! How can that be? And what's the recommended way to cache a child VNode to avoid calling Child::change when Parent::view is called?

Boscop avatar Mar 16 '20 20:03 Boscop