GithubHelp home page GithubHelp logo

gaearon / component-router Goto Github PK

View Code? Open in Web Editor NEW

This project forked from nkbt/component-router

1.0 2.0 1.0 1.75 MB

Flux-based component routing solution

License: MIT License

JavaScript 99.30% CSS 0.70%

component-router's Introduction

component-router

Circle CI Coverage Status Dependency Status devDependency Status

Flux-based partial routing solution

Not a replacement for react-router. Could be used as addition to it. Or standalone.

WARNING Work in progress, though most of the functionality is there.

See issues for more info on what is going to happen.

Idea

The idea of partial routing is coming from the need to track state of independent components in the URL.

Commonly used routers are mostly hierarchical. The great example of such a router is react-router. Unfortunately it is not possible to store component's state independently from the other component in a different "branch" of hierarchy.

They work perfectly for most of the UIs. But as soon as we are trying to build a complex UI with multiple independent components and each of those has own state you would like to preserve, it becomes a challenging task. ComponentRouter was created to provide a simple way of keeping such state in the URL with query params.

Here is an example of such interface.

  1. Chart block, which can be switched from bar to pie
  2. Filter block, that can be opened or closed
  3. Data panel with two tabs: sources and destinations
+------------------------------------------------------------------------------+
|  App "/app"                                                                  |
|                                                                              |
|  +------------------------------+  +---------------------------------------+ |
|  |  chart                       |  |  filter                               | |
|  |  [->bar] [pie]               |  |  [->opened] [closed]                  | |
|  |                              |  |                                       | |
|  |                              |  |                                       | |
|  |                              |  |                                       | |
|  |                              |  |                                       | |
|  |                              |  |                                       | |
|  +------------------------------+  +---------------------------------------+ |
|                                                                              |
|  +---------------------------------------------------+                       |
|  |  data                                             |                       |
|  |  [->sources] [destinations]                       |                       |
|  |                                                   |                       |
|  +---------------------------------------------------+                       |
|                                                                              |
+------------------------------------------------------------------------------+ 

As you can see each of these blocks has its own independent navigation and, for example, Filter can be closed or opened independently from currently displayed Chart type or Data tab selected.

  1. We can always keep the state of each block, but you will loose that state on page refresh.
  2. We can keep their states in some specialized Flux Store and cache in localStorage or even user settings in database on the server. But we are losing ability to share this page with someone else (unless we have some special "copy/paste state" functionality)
  3. At last we can keep state of each component in the URL as query parameter, which solves both problems. Current URL will be: /app?chart=bar&filter=opened&data=sources

Key feature is to update all links on the page if any of visible blocks changed its state. If lets all links to stay links, so it is possible to open link in a new tab, for instance. It is fixed by ComponentRouter.

Minimal Example

import React from 'react';
import {ComponentRouter, Url, LocationHtml5} from 'component-router';


const Baz = React.createClass({
render() {
  const {value} = this.props.componentRouter;
  return <h1>{value && value.toUpperCase()}</h1>;
}
});

const App = React.createClass({
render() {
  return (
    <div>
      <LocationHtml5 />
      <Url query={{baz: 'foo'}}>Foo</Url> | <Url query={{baz: 'bar'}}>Bar</Url>
      <ComponentRouter config={Baz} namespace="baz" />
    </div>
  );
}
});

React.render(<App />, document.body);

foobar.gif

You can run the Minimal example with npm run foobar, it is shipped with the source code.

Quick-start

Quick-start is a step-by-step walk-through to implement UI based on ASCII example from above.

1. Install component-router from npm

npm install --save component-router

2. Add App and main blocks: Chart, Filter, Data

import React from 'react';

const Chart = React.createClass({
render() {
  return <h2>Chart</h2>;
}
});


const Filter = React.createClass({
render() {
  return <h2>Filter</h2>;
}
});


const Data = React.createClass({
render() {
  return <h2>Data</h2>;
}
});


const App = React.createClass({
render() {
  return (
    <div>
      <Chart />
      <Filter />
      <Data />
    </div>
  );
}
});

React.render(<App />, document.body);

3. Add second-level blocks (not yet used for now)

const ChartBar = React.createClass({
render() {
  return <h3>Bar</h3>;
}
});

const ChartPie = React.createClass({
render() {
  return <h3>Pie</h3>;
}
});

const FilterClosed = React.createClass({
render() {
  return <h3>Closed</h3>;
}
});

const FilterOpened = React.createClass({
render() {
  return <h3>Opened</h3>;
}
});

const DataSources = React.createClass({
render() {
  return <h3>Sources</h3>;
}
});

const DataDestinations = React.createClass({
render() {
  return <h3>Destinations</h3>;
}
});

4. Add ComponentRouter

Wrap each main component, give it a namespace and config

Also render Location provider (LocationHtml5 for History-API links or LocationHtml4 for hash-links).

import {ComponentRouter, LocationHtml5} from 'component-router';
//...

const App = React.createClass({
render() {
  return (
    <div>
      <ComponentRouter namespace="chart"
        config={{bar: ChartBar, pie: ChartPie}}>
        <Chart />
      </ComponentRouter>
      <ComponentRouter namespace="filter"
        config={{opened: FilterOpened, closed: FilterClosed}}>
        <Filter />
      </ComponentRouter>
      <ComponentRouter namespace="data"
        config={{sources: DataSources, destinations: DataDestinations}}>
        <Data />
      </ComponentRouter>
    </div>
  );
}
});

5. Update your main components with links

Note that wrapper will provide componentRouter object to the props of container component.

For now we will use only namespace and Component. First just passes namespace down, second should be rendered wherever we want to have our route handler component.

We will also use Url component provided by component-router to render dynamic links (they will be updated when any of ComponentRouter blocks changes its state.

import {Url} from 'component-router';

onst Chart = React.createClass({
render() {
  const {namespace, Component} = this.props.componentRouter;
  return (
    <div>
      <h2>Chart</h2>
      <Url query={{[namespace]: 'bar'}}>Bar</Url>
      <Url query={{[namespace]: 'pie'}}>Pie</Url>
      <Component />
    </div>
  );
}
});


const Filter = React.createClass({
render() {
  const {namespace, Component} = this.props.componentRouter;
  return (
    <div>
      <h2>Filter</h2>
      <Url query={{[namespace]: 'opened'}}>Open</Url>
      <Url query={{[namespace]: 'closed'}}>Close</Url>
      <Component />
    </div>
  );
}
});


const Data = React.createClass({
render() {
  const {namespace, Component} = this.props.componentRouter;
  return (
    <div>
      <h2>Data</h2>
      <Url query={{[namespace]: 'sources'}}>Sources</Url>
      <Url query={{[namespace]: 'destinations'}}>Destinations</Url>
      <Component />
    </div>
  );
}
});

6. PROFIT

Compile your code, the routing is now completed.

Quickstart.gif

NOTE href changes, so we can open link in new tab.

You can run the full Quickstart example with npm run example, it is shipped with the source code.

Development and testing

To run comprehensive example covering all ComponentRouter features, use npm start, which will compile src/example/Example.js

git clone [email protected]:in-flux/component-router.git
cd component-router
npm install
npm start

# then
open http://localhost:8080

To run Foobar example, use npm run foobar

To run Quick-start example, use npm run quickstart

Demo

http://nkbt.github.io/component-router/example

Tests

  1. UI for manual testing - npm start, open http://localhost:8080
  2. Automated tests are in ./test and should be run with npm run test:dev (watch mode)
  3. Coverage report is generated by running npm run test:cov

License

MIT

component-router's People

Contributors

nkbt avatar

Stargazers

 avatar

Watchers

 avatar  avatar

Forkers

rubythonode

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.