/reactor-router

Opal Ruby wrapper for React Router

Primary LanguageRubyMIT LicenseMIT

ReactiveRouter

ReactiveRouter allows you write and use the React Router in Ruby through Opal.

Note

This gem is in the process of being re-written. It will be based on latest react-router which is way better. Please see the v2-4-0 branch. If you you want to use this branch with reactive-rails-generator, be sure to remove require 'react_router from components.rb. And to use the new Router syntax as per the docs.

Installation

Add this line to your application's Gemfile:

gem 'reactive-router'

And then execute:

$ bundle

Or install it yourself as:

$ gem install reactor-router

Usage

The router is a React component that loads other components depending on the current URL.

Unlike other compnents there can only be one router on a page.

To get you started here is a sample router.

module Components
  module Accounts

    class Show

      include React::Router  # instead of React::Component, you use React::Router
      
      # the routes macro creates the mapping between URLs and components to display

      routes(path: "/account/:user_id") do  # i.e. we expect to see something like /account/12345
        # routes can be nested  the dashboard will be at /account/12345/dashboard
        # the DashboardRoute component will be mounted
        route(name: "Dashboard", path: "dashboard", handler: Components::Accounts::DashboardRoute)
        route(path: "orders", name: "Orders", handler: Components::Accounts::OrdersRoute)
        # when displaying an order we need the order order as well as the user_id
        route(path: "orders/:order_id", name: "Order", handler: Components::Accounts::OrderRoute)
        route(path: "statement", name: "Statement", handler: Components::Accounts::StatementRoute)
        # the special redirect route 
        redirect(from: "/account/:user_id", to: "Dashboard")
      end
      
      # you grab the url params and preprocess them using the router_param macro.
      # when Router is mounted it will receive the :user_id from the url.  In this case we grab
      # the corresponding active_record model.
      
      router_param :user_id do |id|
        User.find(id)
      end

      # like any component routers can have params that are passed in when the router is mounted

      param :user_param, type: User
      param :user_orders_param, type: [Order]
      param :production_center_address_param, type: Address
      param :open_invoices_param
      param :user_profiles_param, type: [PaymentProfile]
      param :user_addresses_param, type: [Address]
      
      # because the underlying javascript router has no provisions to pass params we
      # will export states and copy the params to the states so the lower components can read them
      # expect this get fixed in the near future

      export_state :user
      export_state :production_center_address
      export_state :open_invoices
      export_state :payment_profiles
      export_state :addresses
      
      # the router also makes a good place for other top level states to be housed (i.e. the flux architecture)
      export_state :order_count

      before_mount do
        # before mounting the router we copy the incoming params that the lower level components will need
        user! user_param
        production_center_address! production_center_address_param
        open_invoices! open_invoices_param
        payment_profiles! user_profiles_param
        addresses! user_addresses_param
        
        order_count! user.orders.count  # grab our top level state info and save it away
        
      end

      # For routers you define a show method instead of a render method
      def show
        div do
          div.account_nav do
          
            # link is a special router component that generates an on page link, that will maintain history etc.
            # basically an intelligent anchor tag.  When a user clicks a link, it will rerender the router, update
            # the history etc.
            # So for example when "My Statement" is clicked. The route changes to /account/:id/statement
            
            link(to: "Dashboard", class: "no-underline btn btn-default", params: { user_id: user.id }) { "Account Dashboard" }
            link(to: "Orders", class: "no-underline btn btn-default", params: { user_id: user.id }) { "My Quotes & Orders" }
            link(to: "Statement", class: "no-underline btn btn-default", params: { user_id: user.id }) { "My Statement" }

          end
        # someplace in the router show method you will have route_handler component which mounts and renders the component
        # indicated by the current route.
        route_handler   
        end
      end
    end
    
    # We can't pass parameters to the routed components, so we set up these mini components
    # which grab the state from router and send it along to the actual component
  
    class DashboardRoute

      include React::Component

      def render
        AccountDashboard user: Show.user, addresses: Show.addresses, payment_profiles: Show.payment_profiles
      end

    end

    class StatementRoute

      include React::Component

      def render
        Statement production_center_address: Show.production_center_address,
        open_invoices: Show.open_invoices, current_invoices: Show.open_invoices[:invoices],
        mailing_address: Show.open_invoices[:mailing_address]
      end

    end

    class OrdersRoute

      include React::Component

      def render
        AccountOrders user: Show.user #, orders: Show.orders
      end

    end

    class OrderRoute

      include React::Component

      router_param :order_id do |id|
        Order.find(id)
      end

      def render
        OrderShow(order: order_id, referrer: "account")
      end

    end
    
  end
end

Development

After checking out the repo, run bin/setup to install dependencies. Then, run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release to create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

  1. Fork it ( https://github.com/catprintlabs/reactor-router/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request