zetachang / react.rb

Opal Ruby wrapper of React.js library.
http://reactrb.org/
MIT License
547 stars 35 forks source link

Stateless Components #104

Open catmando opened 8 years ago

catmando commented 8 years ago

React now has this notion of a "stateless" component, by which they mean a JS function that takes the "props" as it param, and generates an element.

Its stateless because there is no react state of any sort.

Just wondering if we should bother and what it would look like?

I guess there might be some value? Consider this:

class Foo < React::Component::Base

   def search_tag(url, name)
      a(href: "https://www.google.com/#q=#{name}") { name }
   end

   def render
      div { search_tag("Joe") }
   end
end

and now this:

class SearchTag < React::Component::Base
  param :name, type: String 
  def render
     a(href: "https://www.google.com/#q=#{params.name}") { params.name }
  end
end

class Foo < React::Component::Base
  ... assume Foo has some parameters and/or state
   def render
        ... assume Foo is rendering some other stuff too
          div { SearchTag("Joe") }
   end
end

In the second case, we will never re-render SearchTag, because its param never changes, and it has no state. In the first case everytime Foo is rendered so is the anchor tag.

So I see the value, but I am not sure how to ruby-ize this...

derikson commented 8 years ago

Just as in JavaScript, stateless components could be created in Ruby as functions. Consider:

def SearchTag(name:)
  a(href: "https://www.google.com/#q=#{name}") { name }
end

# optional
React::Component.param_types(:SearchTag) do
  param :name, type: String
end
catmando commented 8 years ago

@derikson - good point. The difficulty I think is more "syntactic" as in how to get this to all work nicely within the DSL, such that its easy to create stateless components.

A lot of the DSL mechanism comes along with being inside of a React::Component::Base class, so its not clear how to declare a component without declaring the class wrapper, and a render method.

Some important background: In 0.8 (or 0.9 maybe) we will be merging the "define_state" and "export_state" macros to a single "state" macro and making it mandantory (currently its optional for non exported states.)

Also in 0.8 you will have to prefix params and state with the "params" and "state" methods.

Given this:

One approach would be to have a class React::Component::StatelessBase that simply removes the state macro, and has no state instance method. An exception would be raised if the component accessed any external state.

class SearchTag < React::Component::Stateless
  param: name, type: String
  def render
    a(href: "https://www.google.com/#q=#{params.name}") { params.name }
  end
end

its a lot of boiler plate.... how about

React::Component.define(:SearchTag) do 
   param :name, type: String
   a(href: "https://www.google.com/#q=#{params.name}") { params.name }
end

I think it would be possible to implement this...

sollycatprint commented 8 years ago

This issue was moved to reactrb/reactrb#104