rubyreactjsopalrbreact.rb

Having trouble with opal and trying to render out a simple react.rb template


I'm trying to use the react.rb gem with opal however I'm having trouble with it.

The following is a simple hello world component, nothing complex.

class Hello_World
    include React::Component

    define_state(:message) { "Hello World!" }

    def initialize(native)
        @native = native
    end

    def component_will_mount
        puts self.message
    end


    def render
        div do
            span do
                self.message
            end
        end
    end

end

Doing this:

puts React.render_to_static_markup(React.create_element(Hello_World))

gets me what I expected, this:

Hello World!
<div><span>Hello World!</span></div>

The problem is when I try to render the template to the dom.

This:

 React.render React.create_element(Hello_World), `document.body`

just gives me:

Uncaught Error: Invariant Violation: _registerComponent(...): Target container is not a DOM element.

So I thought it was becuase document.body doesn't exist yet, however none of the following to access the window work (or document):

window #is undefined

$window # is nil

Window # is undefined

There doesn't seem to be an opal command doc for JS equivalents and none of the examples I can find work.

I'm on the verge of pulling my hair out, what do I do?

EDIT:

Doing the following actualy works:

I'm not using jquery so I have to do the following to get document.ready:

document.ready = function (event) {
    document.addEventListener("DOMContentLoaded", event)
}

%x|document.ready(function(){
    #{
        React.render React.create_element(Hello_World), `document.getElementById('mount_point')`
    }
})|

but it's suuuuper hacky.


Solution

  • The problem is that body.getElementById('mount_point') was returning nil, this was because the script was executing before the dom was ready.

    Since I'm not using Jquery and for some reason I couldn't access the document object I was having trouble. In the end though I was able to create a method to deal with that for me.

    So, defining this:

    def ready
        %x|document.addEventListener("DOMContentLoaded", function(){
            #{yield}
        })|
    end
    

    allows me to do:

    ready do
        React.render React.create_element(Hello_World), `document.getElementById('mount_point')`
    end