-
Notifications
You must be signed in to change notification settings - Fork 29
Reactive State
The full power of react comes from updating state and having the effected components re-render.
States in react act very much like Ruby instance variables, with the added feature that when the state variable changes it causes the component instance to be re-rendered. Like params (react.js props) states in Reactive-Ruby work exactly like in react.js, but again with some added love.
Lets compare the syntax for React.js and Reactive Ruby states.
var CommentBox = React.createClass({
getInitialState: function() {
return {data: []};
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
});and in Ruby
class CommentBox
include React::Component
define_state data: [] # The form define_state :data will initialize to nil
def render
div.commentBox do
h1 { "Comments" }
CommentList data: data # like params declaring a state creates a instance method for you but
# you could still say state[:data] too.
comment_form # comment_form is an instance method we will define later on
end
end
endSo far not much is going to happen unless we have a way to update that state. Lets poll a server to get the up to date comments:
class CommentBox
# one nice thing about ruby is we can open our component class and add to it.
# in this case its a bit artificial, but it can be useful in structuring a large component.
required_param :url, type: String
optional_param :poll_interval, default: 60
after_mount do
every(poll_interval) do # we use the opal browser utility to call the server every poll_interval seconds
HTTP.get(url) do |response|
if response.ok?
data! JSON.parse(response.body)
else
puts "failed with status #{response.status_code}"
end
end
end
end
endEvery state has a getter method (the state name) and a setter method (the state name followed by a "!"). The setter method can take a parameter (the new state value) and it will update the state, and notify react of the change. THe setter method returns the current value (before updating) which is often handy. Under the hood it uses the react setState function to accomplish its work.
So now we need a way to add a comment to the data base, that will be the work of our comment_form method and its helper submit_comment.
For the purpose of this tutorial we make comment_form as method. In reality you would probably make it a separate component.
class CommentBox
define_state author: ""
define_state text: ""
def comment_form
div do
div do
"Author: ".span
input.author_name(type: :text, value: author, placeholder: "Your name", style: {width: "30%"}).
# and we attach an on_change handler to the input. As the input changes we simply update author.
on(:change) { |e| author! e.target.value }
end
div do
# lets have some fun with the text. Same deal as the author except we will use a text area...
div(style: {float: :left, width: "50%"}) do
textarea(value: text, placeholder: "Say something...", style: {width: "90%"}, rows: 30).
on(:change) { |e| text! e.target.value }
end
end
button { "Post" }.on(:click) { submit_comment author: author!(""), text: text!("") }
end
end
def submit_comment(comment = {})
HTTP.post(url, payload: comment) do |response|
puts "failed with status #{response.status_code}" unless response.ok?
end
comments! << comment # notice the second form of the setter method is being used here
end
endA key feature of the above code is the line comments! << comment. Notice that the setter method is not given a parameter. In this form the setter method returns the current value of comments wrapped in an observer which is a unique Reactive Ruby construct. The observer object will act just like the object it wraps, but reports any method calls to the object as state changes to react. Observers have other features as well and together they accomplish a lot of the work of react links, and flux notifiers.
So in the case of comments! << comment what happens is the current value of comments (an array) is returned as an observer, and the array push method is applied. This updates the underlying value of the comments array, but also notifies react that state has changed. The end result is less book keeping, and the benefits of "pure" objects without the overhead.
Of course this is just an augmentation of the underlying react system. You still have access to the react state object, and can use it if needed to directly update state that way.