remix-run / react-router

Declarative routing for React

Home Page:https://reactrouter.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Lazy loading support

yongxu opened this issue · comments

Route does not support lazy loading, in order to use this feature, all routes has to be written in plain route like this:

module.exports = {
  path: 'course/:courseId',

  getChildRoutes (state, cb) {
    require.ensure([], (require) => {
      cb(null, [
        require('./routes/Announcements'),
        require('./routes/Assignments'),
        require('./routes/Grades'),
      ])
    })
  },

  getComponents (cb) {
    require.ensure([], (require) => {
      cb(null, require('./components/Course'))
    })
  }
};

Currently react router does not allow mixed array of Route and plain route, in order to use lazy loading we have to replace all the Routes with plain routes, which is quite annoying. This is easy to fix but I think we should have better support for this usage.
I have made a simple pull request #1817 to allow Route mix with plan route, so that it allows user to do this:

<Route name="lazy" path="/lazy" plainRoute={require("your_plain_route")} />

or

<Route name="lazy" path="/lazy" plainRoute={{
  getComponents (cb) {
    //load lazily, asynchronously and only called when needed
    require.ensure([], (require) => {
      cb(null, require('your_lazy_component'))
    })
  }
}}>

Later I also found there was another solution, #1776, which I think is very useful too:

pass in the state params to the user defined getComponents method.

<Router handler={App}>
    <Route name='calendar' path='calendar' components={CalendarMaster}>
        <Route name='type' path=':typename/:id' getComponents={typeHandler}>
            <Route name='period' path=':period' getComponents={periodHandler} />
        </Route>
    </Route>
</Router>

Maybe we could even support something much simpler? This doesn't seem to work with webpack without extra work, but it looks great:

<Route name="lazy" path="/lazy" source="urlHere?" />

You can already do

function getChildRoutes() {
  require.ensure([], function (require) {
    // go nuts.
  })
}

<Route path="/lazy" getChildRoutes={getChildRoutes} />

Thanks @mjackson , I still have a question,
if we use

<Route path="/lazy" getChildRoutes={(state, cb)=> {
    require.ensure([], (require) => {
      cb(null, [
        require('./routes/inner')
      ])
    })} />

to replace this:

module.exports = {
  path: 'outer',
  getChildRoutes (state, cb) {
    require.ensure([], (require) => {
      cb(null, [
        require('./routes/inner')
      ])
    })
  },
};

don't we still have to getComponents again to grab the actual component?

//required by require('./routes/inner')
module.exports = {
  path: 'actual_component',

  getComponents (cb) {
    require.ensure([], (require) => {
      cb(null, require('./components/what_I_want_to_load'));
    })
  }
};