Hyperapp: Diffing algo. forces re-render with respect to no dependency on state

Created on 10 Jan 2018  ·  8Comments  ·  Source: jorgebucaran/hyperapp

Hello,

I created a state variable representing the latest time which is updated every second, and pass it only to components which rely on time.

const main = logger()(app)(state, actions, view, document.body);
setInterval(main.time, 1000);
export default {
    time: () => state => ({time: new Date()}),
    ...order
}

In my main view, I currently reference state.time in only one component. For some reason though, the entire view gets patched from state.time being updated.

export default (state, actions) =>
    <Layout>
        {/* Header */}
        <GridItem x={1} y={1} xs={-1} ys={1}><NavBar time={state.time}/></GridItem>

        {/* Left Column */}
        <GridItem x={1} xs={5} y={2} ys={8}>
            <Panel>
                <Header>Order</Header>
                <OrderForm order={state.order} actions={actions.order}/>
            </Panel>
        </GridItem>
        ...

I found out the whole view was being re-rendered as the functional component keeps on continuously being called. This also forces picostyle which is what I am using to style the components to regenerate classes for all components being re-rendered every second.

export const GridItem = (props, children) => {
    console.log(props)
    return styled("div")({
        gridColumn: `${props.x || ''}${props.x && props.xs && ' / ' || ''}${props.xs && ((props.xs !== -1 && `span ` || '') + props.xs) || ''}`,
        gridRow: `${props.y || ''}${props.y && props.ys && ' / ' || ''}${props.ys && ((props.ys !== -1 && `span ` || '') + props.ys) || ''}`,
    })
    (props, children);
}

image

diff

Does anyone have any ideas on how to not have state.time trigger an entire re-render?

Inquiry Website

All 8 comments

You can memoize portions of your view you don't wish to be patched. In the code snippet GridItem looks like a good place to memoize since it would avoid the picostyle overhead you mentioned.

@andyrj Ah yeah that's a good solution :+1: Though, is there any reason why the view is being re-rendered again (such that the functional component is called again) or am I misunderstanding how the render loop works for Hyperapp?

@iwasaki-kenta I think it's caused by picostyle's strategy, everytime your state changes, hyperapp wants to diff old vnodes tree and the new one. So it has to call your styled function to compute the new one.

@iwasaki-kenta , other than memoization, you might figure out a way to replicate redux reselect for hyperapp which could eliminate renders for updates that don't change some subset of your state. Otherwise hyperapp doesn't try to automatically optimize your functional components at this point. I assume picostyle is sending new references for it's computed inline styles, which will cause those covered with picostyle to always re-render, outside of memoization. As far as I am aware react doesn't give pure functional components any special willComponentUpdate, that's only on the class based components.

What behavior were you looking for? If you expect auto memoization how would we do that without breaking things/causing other issues?

In my opinion leaving memoization to the user is the best option.

Also since picostyle is going to do this for every user, adding memoization to that libraries styled() might be neat to consider also.

@iwasaki-kenta Does anyone have any ideas on how to not have state.time trigger an entire re-render?

Render means to call the view function to produce a new virtual node tree and then patch the DOM with it. We are —not— creating new elements, only updating their attributes (setAttribute(element, attribute, value)), hence the flashing. To avoid calling the view function when your view is mostly static, I'd suggest to follow @andyrj's advice and memoize it for now.

I am, however, interested in exploring "auto-memoization" of views, but perhaps in a separate issue? 🙏

@andyrj @JorgeBucaran Thanks a lot for the explanations!

In this case, I'll look into writing up a patch for picostyle for memoizing styled components :grin:.

For memoizing views somewhat like redux-reselect which @andyrj mentioned, I definitely am interested in having that to reduce updates to the DOM with respect to state. Though of course lets leave that for another issue.

I recalled this issue and thought I'd share a similar issue that touches on memoization from https://github.com/jorgebucaran/superfine/issues/148.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jamen picture jamen  ·  4Comments

jorgebucaran picture jorgebucaran  ·  3Comments

zaceno picture zaceno  ·  3Comments

dmitrykurmanov picture dmitrykurmanov  ·  4Comments

SkaterDad picture SkaterDad  ·  3Comments