Skip to content
This repository has been archived by the owner on Oct 19, 2018. It is now read-only.

Store Anatomy

Mitch VanDuyn edited this page Jan 24, 2017 · 12 revisions

Stores are where the state of your Application lives

Anything but a completely static web page will have dynamic states that change because of user inputs, the passage of time, or other external events.

Stores are Ruby classes that keep the dynamic parts of the state in special state variables

For example here is Store that keeps track of time at a given location:

class WorldClock < HyperStore
  # Keep track of the time at multiple locations 
  attr_reader :name
  attr_reader :lattitude
  attr_reader :longitude
  attr_reader :time_zone_offset

  def current_time
    WorldClock.gmt+time_zone_offset
  end

  def initialize(name, lattitude, longitude, time_zone_offset)
    @name, @lattitude, @longitude, @time_zone_offset = 
      [name, lattitude, longitude, time_zone_offset]
  end

  def WorldClock.gmt
    unless state.gmt
      every(1) { state.gmt! = Time.now.gmt }
      state.gmt! = Time.now
    end
    state.gmt
  end
end  

Now we can create a clock and post the time to the console every minute like this:

new_york = WorldClock.new('New York', 40.7128, -74.0059, 5.hours)
every(1.minute) { puts new_york.current_time }  

But because it is a Reactive Store we can also say this:

# assume we have a div with id='new-york' some place in our code
Element['div#new-york'].render do 
  "The time in #{new_york.name} is #{new_york.current_time}"
end

This will automatically rerender the contents of the 'new-york' DIV whenever the store changes!

Notice that the current_time method uses the gmt method, where we update and access a state variable named state.gmt. State variables work the same as Ruby instance variables like @name, except that when they change, all the parts of the display that are depending on the current value will be updated.

So when we first render our 'new-york' DIV, current_time calls gmt, which reads the value of state.gmt. Our store now "knows" that when state.gmt changes that DIV will have to be re-rendered.

To alert the reader of the code that we are changing the state, the name of the state variable has the exclamation mark (!) appended to it when it is changed or modified.

Stores are like Flux Stores

If you have heard of or used Flux, then this is the same idea but extended to keep things easy.

  • A store can be a singleton class (as in Flux)
  • or it can have many instances (like our example above.)
  • The wiring up between stores, actions, dispatchers, components and promises is largely automatic.
  • A store is a Ruby class and you are encouraged to use good data abstraction to hide the internal representation of your store.

Keep Stores Simple

Stores are Ruby Classes, so you may be tempted to add more intelligence than needed to the Store. Hyperloop suggests (but does not force) you keep the logic in a Store to the minimum needed to keep the data structures intact.

In the WordClock Store we delegate the computation of the name, latitude, longitude and time zone, upwards, to the caller, and avoid the temptation to automatically figure this all out based on say the name. Elsewhere we will see that Operations are the best place to put that logic.

In general, Hyperloop would recommend that you keep all Store code synchronous. This mainly means don't try to make HTTP requests or call other methods that return promises that will resolve in the future. The one reasonable exception to this is periodic events like the WorldClock uses.
This may not be true... Probably the only consideration is keeping the store simple.

Clone this wiki locally