# Rerendering on widget keyUp / keyDown?

**URL:** https://meta.discourse.org/t/rerendering-on-widget-keyup-keydown/61461
**Category:** Development
**Created:** [April 23, 2017, 2:02pm UTC](https://meta.discourse.org/t/rerendering-on-widget-keyup-keydown/61461 "2017-04-23T14:02:30Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![gdpelican](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/gdpelican/32/81308_2.png) [@gdpelican](https://meta.discourse.org/u/gdpelican)
#### Post date: [April 23, 2017, 2:02pm UTC](https://meta.discourse.org/t/rerendering-on-widget-keyup-keydown/61461/1 "2017-04-23T14:02:30Z")

</div>

Hey Discourse team,

I’m currently investigating why Babble slows down user input so much while typing. I’ve traced it to the keyUp / keyDown hooks in my composer widget, which do things like listen for submit on enter, and escape to cancel, as well as sending notifications that the user is currently typing.

It looks like those events go into a `nodeCallback` function in `discourse/widgets/hooks`, which looks like this (NB that this is simplified a bit):

```plaintext
function nodeCallback(widget, keyDownFn) {
  widget.scheduleRerender(() => keyDownFn(widget));
}

```

Thing is… I _really_ don’t want to rerender the widget on each keystroke, especially because it triggers a rerender of the whole widget tree:

```plaintext
function scheduleRerender() {
  var widget = this;
  while (widget) {
    // rerender the widget if possible
    widget = widget.parentWidget
  }
}

```

I’m wondering if it’s preferable here to allow the widget to define which events it wants to rerender on, like so:

```plaintext
  createWidget('my-widget', {
    skipKeyUpRerender: true
  })

```

or whether we can simply turn off rerendering for keyUp / keyDown events, and have the developer manually call `scheduleRerender` on those if necessary (since they have the potential to be quite high-volume events)

(I haven’t found any existing Discourse code which utilizes the keyUp / keyDown hooks in widgets, so I guess I’m battle testing them 😛 ⚔ )

cc @eviltrout

---

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [April 24, 2017, 6:55pm UTC](https://meta.discourse.org/t/rerendering-on-widget-keyup-keydown/61461/2 "2017-04-24T18:55:05Z")

</div>

Hmm this is tricky. The widget framework is designed to re-render following any input, be it clicking or pressing a key. In general re-rendering widgets is fast, so the thought was you should be able to re-render as fast as the user is typing.

Are your renders slow? You can output how many ms are being taken by adding `profileWidget: true` to its definition.

---

<div class="post-metadata">

### Author: ![gdpelican](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/gdpelican/32/81308_2.png) [@gdpelican](https://meta.discourse.org/u/gdpelican)
#### Post date: [April 25, 2017, 4:09am UTC](https://meta.discourse.org/t/rerendering-on-widget-keyup-keydown/61461/3 "2017-04-25T04:09:28Z")

</div>

My guess would be that the render may be slow because it’s traversing up the widget tree and rerendering the whole chat pane (including all of the posts, which are their own widget), whereas if it rerenders on keyUp I’d love it to just rerender the composer (which I reckon would be quite fast).

```plaintext
- slide in menu <-- (this gets rerendered on composer keyUp)
  - chat pane
     - potentially a whole ton of posts
  - composer

```

Need to confirm this though; will have a go at profiling this later today / tomorrow.

---

<div class="post-metadata">

### Author: ![gdpelican](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/gdpelican/32/81308_2.png) [@gdpelican](https://meta.discourse.org/u/gdpelican)
#### Post date: [April 30, 2017, 10:36pm UTC](https://meta.discourse.org/t/rerendering-on-widget-keyup-keydown/61461/4 "2017-04-30T22:36:18Z")

</div>

Okay, I can confirm this. With a small amount of posts loaded in the window, the rendering times are acceptable (40-60ms each for keyUp / keyDown)

However, as more posts are loaded into the window, the rendering time of the widget gradually increases:  
50 posts: ~50ms  
100 posts: ~70ms  
150 posts: ~100ms  
200 posts: ~130ms

etc.

There’s certainly a scaling issue here, but it doesn’t really manifest itself except that it’s rerendering on keyUp _and_ keyDown 😕 (I need both for separate events), meaning we get to that 300ms limit of human perception quite quickly.

---

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [May 1, 2017, 7:20pm UTC](https://meta.discourse.org/t/rerendering-on-widget-keyup-keydown/61461/5 "2017-05-01T19:20:13Z")

</div>

Are the posts in the window using the `shadowTree` property that our [post stream](https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/widgets/post.js.es6#L387) does?

If you set that attribute, the virtual dom will not diff the contents of posts on a typical re-render. It _will_ diff if something inside the post triggers the render (such as an action on a button on it).

You might notice a huge speed improvement if you implement this. Of course, it makes the assumption that posts only change as a result of interacting with them directly.

---

<div class="post-metadata">

### Author: ![gdpelican](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/gdpelican/32/81308_2.png) [@gdpelican](https://meta.discourse.org/u/gdpelican)
#### Post date: [May 1, 2017, 11:32pm UTC](https://meta.discourse.org/t/rerendering-on-widget-keyup-keydown/61461/6 "2017-05-01T23:32:18Z")

</div>

Cool, I _think_ that’s exactly what I’m looking for!
