winjs / react-winjs

React wrapper around WinJS's controls
MIT License
206 stars 47 forks source link

ListView within a Pivot not re-rendering? #27

Closed staxmanade closed 9 years ago

staxmanade commented 9 years ago

Hey All,

First I'd like to say thanks for creating this. While I'm not particularly excited with the "magic" I don't yet understand on the layers of abstraction added, I am very interested in how much easier it is to reason about building WinJS apps using React...

I am struggling to debug the following scenario.

I've created a SearchHub component (think of this component as very similar to the example search movies http://winjs.github.io/react-winjs/examples/movies/index.html component).

The biggest difference is I'm trying to place it inside of a Pivot control.

When the app first loads up and I search, it fills out the ListView great. I click on the item to navigate to the details view. When I come back the ListView is not re-rendering and is blank...

My first issue was due to React state problem, but I've worked out the state correctly. If I use the SearchHub component by itself it correctly re-renders the ListView on back navigation. However once placed inside a PivotItem back navigation does not appear to correctly render the ListView.

Correctly renders search/listView on back navigation from details page

return (
                // <Pivot style={pivotStyle}>
                //     <Pivot.Item key="search" header="Search">
                        <SearchHub search={this.state.search} />
                //     </Pivot.Item>
                //     <Pivot.Item key="featured" header="Featured">
                //         <FeaturedHub />
                //     </Pivot.Item>
                // </Pivot>
    }

Does NOT render search/listView on back navigation from details page

return (
                <Pivot style={pivotStyle}>
                    <Pivot.Item key="search" header="Search">
                        <SearchHub search={this.state.search} />
                    </Pivot.Item>
                    <Pivot.Item key="featured" header="Featured">
                        <FeaturedHub />
                    </Pivot.Item>
                </Pivot>
    }

Any thoughts or tips on how to debug this?

staxmanade commented 9 years ago

NOTE: the input search box IS rendering correctly - so it's not the whole view inside the pivot having issues, just the ListView...

staxmanade commented 9 years ago

Hmm, I was going to try to repro in a Plunk - but struggling to get it to render the original data now :(

Edit: Here is a working Repro of my issue:

http://plnkr.co/edit/4TFrMN?p=preview

If you search, or just select an item in the search to visit the details - when you go back the ListView is empty. You can click on the next tab and click back and it will re-draw correctly.

Any thoughts?

staxmanade commented 9 years ago

I've tried triggering a forceLayout, but no luck there

                <ListView
                    ref={function(listView) {
                        if (listView && listView.winControl) {
                            listView.winControl.forceLayout();
                            console.log("forceLayout");
                        } else {
                            console.log("no forceLayout");
                        }
                    }}
rigdern commented 9 years ago

@staxmanade This is due to a bug in the Pivot introduced in WinJS 4.1. In general, ListViews fail to render inside of a Pivot. I filed an issue for this: winjs/winjs#1497.

In case you are curious, here are additional details. The ListView happens to render inside of the Pivot sometimes in react-winjs due to a race condition. react-winjs calls React.render to render the Pivot Item. If React.render runs synchronously, then the ListView fails to render. If React.render runs asynchronously, then the ListView may render. See winjs/winjs#1497 for more details about the cause.

You should be able to work around this by calling forceLayout() on the ListView -- you just have to make sure this is called after the Pivot Item is visible. A good time to call forceLayout() on the ListView would be in the Pivot's itemanimationend event.

staxmanade commented 9 years ago

Fantastic. I'll go back to my project and give this a try! Thanks for digging in.

staxmanade commented 9 years ago

Thank you @rigdern. I implemented the following work-around based on your suggestion and it's working great.

In the React component where render returns a Pivot I have this:

    hackFixForListView() {
        // due to a bug in WinJS
        // https://github.com/winjs/react-winjs/issues/27
        // we need to forceLayout here for listViews
        console.warn('hackFixForListView called: https://github.com/winjs/react-winjs/issues/27');
        [].slice.call(document.querySelectorAll('.win-listview'))
            .forEach(function(item){
                item.winControl.forceLayout();
            });
    }

On the Pivot control I use this:

                <Pivot onItemAnimationEnd={this.hackFixForListView}>
                    <Pivot.Item key="search" header="Search">
                        <SearchHub search={this.state.search} />
                    </Pivot.Item>
                </Pivot>

This is working great for now. I'll keep an eye on the open WinJS issue and remove the work-around when it's updated.