sergioramos / react-tvml

React bindings to Apple's TVJS and TVML
218 stars 12 forks source link

ITML <Error>: Invariant Violation: processUpdates(): Unable to find child 0 of element. #13

Open enjikaka opened 9 years ago

enjikaka commented 9 years ago
ITML <Error>: Invariant Violation: processUpdates(): Unable to find child 0 of element.
This probably means the DOM was unexpectedly mutated (e.g., by the browser), 
usually due to forgetting a <tbody> when using tables, nesting tags like <form>, 
<p>, or <a>, or using non-SVG elements in an <svg> parent. Try inspecting the 
child nodes of the element with React ID `.1ljayehovsw.1.0.0.1`.

I do not know how to check for .1ljayehovsw.1.0.0.1, can't find a way to debug this. But all my tags are closed correctly. This happens when I try to render <lockup> within <section> in a <grid>.

Snippet:

var React = require('react');
var TVML = require('react-tvml');

var ArtistAlbumListItem = React.createClass({
    render: function() {
        return (
            <lockup>
                <img src={this.props.album.cover} width="256" height="256" />
                <title>{this.props.album.name}</title>
            </lockup>
        );
    }
});

var ArtistAlbumList = React.createClass({
    render: function() {
        var albums = this.props.albums.map(function(album) {
            return (
          <ArtistAlbumListItem key={album.id} album={album} />
        );
        });

        return (
            <grid>
                <section>
                    {albums}
                </section>
            </grid>
        );
    }
});

var ArtistView = React.createClass({
    getInitialState: function() {
        return {
            albums: []
        }
    },
    componentDidMount: function() {
        var self = this;

        var artistId = self.props.id;
        var url = 'https://api.spotify.com/v1/artists/' + artistId + '/albums';

        console.log('I want to load JSON.');

        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.onreadystatechange = function() {
            if (xhr.status === 200 && xhr.readyState === 4) {
                var json = JSON.parse(xhr.responseText);

                var jsonAlbums = [];

                for (var i = 0; i < json.items.length; i++) {
                    var jsonAlbum = json.items[i];

                    jsonAlbums.push({
                        name: jsonAlbum.name + "",
                        cover: jsonAlbum.images[0].url + ""
                    });
                }

                if (self.isMounted()) {
                    self.setState({
                        albums: jsonAlbums
                    });
                }
            }
        };
        xhr.send();
    },
    render: function() {
        return (
            <catalogTemplate>
                <banner>
                    <title>CHVRCHES</title>
                </banner>
                <list>
                    <section>
                        <listItemLockup>
                            <title>Albums</title>
                            <relatedContent>
                                {this.state.albums.length > 0 ? <ArtistAlbumList albums={this.state.albums} /> : <activityIndicator><title>Loading</title></activityIndicator>}
                            </relatedContent>
                        </listItemLockup>
                    </section>
                </list>
            </catalogTemplate>
        );
    }
});

TVML.render(<ArtistView id="3CjlHNtplJyTf9npxaPl5w" />);
sergioramos commented 9 years ago

let me get back to you later ;)

deanmcpherson commented 8 years ago

Hey @ramitos, any update on this? I'm running into similar issues, where pretty much all dom mutations fail, I either get the same error as above or:

<Error>: Invariant Violation: dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a worker thread. Make sure `window` and `document` are available globally before requiring React when unit testing or use ReactDOMServer.renderToString() for server rendering. - http://localhost:9001/public/bundle.js - line:1338:25
adityaj221 commented 8 years ago

+1

boffbowsh commented 8 years ago

The issue is that React expects window and document global variables to be available at require-time. I've been trying to dig into the React internals enough to work out what I need to monkey-patch in this repo, but I'm struggling a bit. If anyone has any deeper React experience, please let me know :)

boffbowsh commented 8 years ago

Made some progress by using Browserify to inject window, document and navigator globals to classes that need them. I'm now coming up against issues in tvOS internals where an IKDOMNodeList (TVJS's version of a NodeList) is assumed by React to be indexable like list[3], but instead you should use list.item(3). This is actually a bug in TVML, and means that their NodeList implementation doesn't obey the specification. I'll try and sort out a workaround :)

sergioramos commented 8 years ago

@boffbowsh I haven't had time to look at this, but window is already being emulated: https://github.com/ramitos/react-tvml/blob/master/src/globals.js

boffbowsh commented 8 years ago

Yes indeed, I think I posted that after a lot of yak shaving. The root issue though is the IKDOMNodeList problem. I might try a beta of the new version of tvOS to see if the issue has been addressed.

deanmcpherson commented 8 years ago

From my experience the DOM implementation looks like it's not completely implemented. Even using list.item(X) syntax, modifying the DOM in some templates doesn't actually reflect itself visually either. This makes sense as the intention behind TVML looks like it encourages you would generate the templates server side and navigate between documents (web 1.0 style).

I built the Townske tvOS app using TVML my own React like framework I wrote for it, but will most likely rewrite it in swift (or React Native if proper support is picked up), as the restrictions imposed design wise by TVML and the lack of a fully functional DOM makes it quite difficult to bend it to your own needs.

emadalam commented 8 years ago

At present the whole TVJS seems a lot buggy and half baked when it comes to DOM api implementations. For instance something as trivial as querySelectorAll is missing, the dynamic update of the DOM causes the whole TVML template to distort in many occasions (try updating any node inside productTemplate), etc. So IMHO using any library that does DOM manipulation, is bound to be buggy. I had to completely drop the idea of using any external library and ended up writing one of my own, atvjs, built on top of TVJS.

Having said that, the ReactJS concept of virtual DOM and diff to issue partial updates to the DOM, may not work in many cases. The best bet is to regenerate the whole document and use replaceDocument method of TVJS navigationDocument class to completely replace the existing DOM with the newly generated one. This might not be the best of the solution, however at present, this is the only foolproof way of updating the DOM.