0.1.1 • Published 6 years ago

react-sidechain v0.1.1

Weekly downloads
2
License
MIT
Repository
github
Last release
6 years ago

react-sidechain

WIP

  • Necessary async component loading in chain.
  • Necessary data loading in chain.
  • Can be used with react-router, @reach/router, may other router frameworks
  • Server side render + Client side render + Single page transition

Usage

Server Side

import { SideChainProvider, SideChainConsumer, SideChainStore, withSideChain } from 'react-sidechain';

async function renderHTML() {
  const store = createStore(); // redux store
  const sideChainStore = new SideChainStore({
    locals: {
      dispatch: store.dispatch,
      getState: store.getState,
    },
    hookNames: ['fetch', 'defer'],
    location: '';
  });

  await sideChainStore.load(App);

  const result = React.renderToString(
    <Provider store={store}>
      <SideChainProvider value={sideChainStore}>
        <StaticRouter
          location={req.url}
          context={context}
        >
          <App sideChainStore={sideChainStore} />
        </StaticRouter>
      </SideChainProvider>
    </Provider>
  );
  return result;
}

Client Side

import { SideChainProvider, SideChainConsumer, SideChainStore, withSideChain } from 'react-sidechain';

async function renderHTML() {
  const store = createStore(); // redux store
  const history = createBrowserHistory();
  const sideChainStore = new SideChainStore({
    locals: {
      dispatch: store.dispatch,
      getState: store.getState,
      getPathname: () => history.location.pathname,
    },
    hookNames: ['fetch', 'defer'],
    location: history.pathname;
  });

  await sideChainStore.load(App);
  sideChainStore.setHookNames(['fetch', 'defer', 'done']);

  // Load data in a side chain
  history.listen(() => {
    sideChainStore.setLocation(location.pathname);
    sideChainStore.load(App);
  });

  const result = React.renderToString(
    <Provider store={store}>
      <SideChainProvider value={sideChainStore}>
        <Router history={history}>
          <App sideChainStore={sideChainStore} />
        </Router>
      </SideChainProvider>
    </Provider>
  );
}
import { matchRoutes, renderRoutes } from 'react-router';

const routes = [{
  exact: true,
  path: '/',
  asyncComponent: () => import('./components/Home'),
}, {
  path: '/about',
  asyncComponent: () => import('./components/About'),
}, {
  path: '/:user',
  asyncComponent: () => import('./components/User'),
}, {
  asyncComponent: () => import('./NoMatch'),
}];

async function defer({dispatch, getState, getPathname, load, setProps, getProps}) {
  const matchedRoutes = matchRoutes(routes, getPathname());
  const promises = matchedRoutes.map( async data => {
    const { route } = data;
    if (route.component) return data;

    const { default: Component } = await route.asyncComponents();
    // Load async component in chain
    await load(Component);
    route.component = Component;
  });
  await Promise.all(promises);
  setProps({
    routes,
  });
}

function done({dispatch, getState, load}) {
  // Only run on client side
  // ...
}

@withSideChain({ defer, done })
class App extends React.Component {
  static propTypes = {
    routes: PropTypes.object,
  }

  render() {
    return renderRoutes(this.props.routes);
  }
}