Scalable reducer management & powerful data fetching for React Router & Redux.
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
example
modules
.babelrc
.eslintrc
.gitignore
CHANGES.md
CODE_OF_CONDUCT.md
CONTRIBUTING.md
LICENSE.md
README.md
package.json

README.md

GroundControl

IMPORTANT! This a beta! Use cautiously until we release 1.0 (then strict semver)! Tests coming...

GroundControl simplifies React-Router/Redux single page applications:

  • Organizes reducers based on route structure, and builds application state & replaces reducers on transition.
  • Data fetching API to control when to render components & manage client / server differences (Universal API).
<Router
    history={browserHistory}
    render={(props) => (
      <GroundControl {...props} store={store} />
    )}>
  <Route path="/" reducer={rootReducer}>
    <IndexRoute reducer={indexReducer} />
    <Route path="/route-1" reducer={route1Reducer} />
  </Route>
</Router>

Demo Clone & npm i && npm start.

Install npm install ground-control --save-dev


Nested application state

Declare a reducer as a property on your routes. Global application state will automatically build. When a nested route changes, that level of state will clear, and reducers replaced...

{
  groundcontrol: {
    self: { currentUser }, // path: "/" -- root component / layout.
    child: {
      self: { items }, // path: "/items" -- 1st level route.
      child: {
        self: { item }, // path: "/items/:id" -- nested
      },
    },
  },
}

...and the data is automatically fed in to your route components.

// { self: { currentUser: 'Nick' }, child: { self: { items: ['a', 'b'] }, child: { self: { item: { quantity: 100 }}}}}
const LayoutComponent = ({ children, data, dispatch }) => (
  <div>
    <p>{data.currentUser}</p>
    <div>{children}</div>
  </div>
);

// { self: { items: ['a', 'b'] }, child: { self: { item: { quantity: 100 }}}}
const ItemsRouteComponent = ({ data }) => <p>{data.items.length}</p>;

// { self: { item: { quantity: 100 }}}
const ItemRouteComponent = ({ data }) => <p>{data.item.quantity}</p>;
Universal data fetching API

Inverse route lifecycle hooks - you tell the framework what to do...

async function asyncEnter(done, { clientRender, serverRender, dispatch, isClient }) => {
  clientRender();
  const topOfPageData = await fetchTopOfPage();
  dispatch(actions.loadTop(topOfPageData));
  serverRender();
  if (isClient()) {
    const bottomOfPageData = await fetchBottomOfPage();
    dispatch(actions.loadBottom(bottomOfPageData));
    done();
  }
};
Redux & friends

Plays nicely (hopefully)...

  • React
  • Redux
  • React Router
  • Universal rendering (isomorphic)
  • Immutable.js
  • Redux Simple Router
  • React-Redux (if desired)
  • Redux DevTools
  • Thunk / middleware
  • Redux-loop
  • Others?

How to use

Contribute

  • API improvements
  • Better documentation
  • Unit tests

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. Multiple language translations are available at contributor-covenant.org

Why GroundControl as a name?

  • Tribute to one of best artists ever
  • Layer above your application to help you control data.
    • API to fetch data for your routes.
    • Clean up state from previous routes.
    • Updates store with new reducers.

Special thanks to ryan florence! Initially based on async-props.