Declarative routing for React

Related tags

Router react-router
Overview

Welcome to React Router · npm package build

React Router is a lightweight, fully-featured routing library for the React JavaScript library. React Router runs everywhere that React runs; on the web, on the server (using node.js), and on React Native.

If you're new to React Router, we recommend you start with the getting started guide.

If you're migrating to v6 from v5 (or v4, which is the same as v5), check out the migration guide. If you're migrating from Reach Router, check out the migration guide for Reach Router. If you need to find the code for v5, it is on the v5 branch.

When v6 is stable we will publish the docs on our website.

Contributing

There are many different ways to contribute to React Router's development. If you're interested, check out our contributing guidelines to learn how you can get involved.

Packages

This repository is a monorepo containing the following packages:

Changes

Detailed release notes for a given version can be found on our releases page.

Funding

You may provide financial support for this project by donating via Open Collective. Thank you for your support!

About

React Router is developed and maintained by Remix Software and many amazing contributors.

Comments
  • Server rendering

    Server rendering

    Route.spec.js contains a commented out test for server rendering but it seems, server rendering would at least require exposing findMatches in the main module.

    Any plans for reintroducing server rendering support?

    opened by simenbrekken 157
  • Rewrite, version 1.0

    Rewrite, version 1.0

    NOTE: DO NOT MERGE YET

    This PR is a complete rewrite of the router with the following goals in mind:

    • simpler top-level API with less boilerplate
    • async route config and/or component loading (better support for code splitting in large apps)
    • simpler API for server-side rendering
    • more React-like <RouteHandler> API
    • easier data fetching API

    ... and a bunch of other stuff that we've learned from various issues over the past year.

    Here's a summary of the various things you can do:

    Top-level API

    var { createRouter, Route } = require('react-router');
    
    var Router = createRouter(
      <Route component={App}>
        <Route name="home" component={Home}/>
      </Route>
    );
    
    // The minimal client-side API requires you to pass a history object to your router.
    var BrowserHistory = require('react-router/lib/BrowserHistory');
    React.render(<Router history={BrowserHistory}/>, document.body);
    
    // On the server, you need to run the request path through the router
    // first to figure out what props it needs. This also works well in testing.
    Router.match('/the/path', function (error, props) {
      React.renderToString(<Router {...props}/>);
    });
    

    The props arg here contains 4 properties:

    • location: the current Location (see below)
    • branch: an array of the routes that are currently active
    • params: the URL params
    • components: an array of components (classes) that are going to be rendered to the page (see below for component loading)

    The branch and components are particularly useful for fetching data, so you could do something like this:

    BrowserHistory.listen(function (location) {
      Router.match(location, function (error, props) {
        // Fetch data based on what route you're in.
        fetchData(props.branch, function (data) {
          // Use higher-order components to wrap the ones that we're gonna render to the page.
          wrapComponentsWithData(props.components, data);
          React.render(<Router {...props}/>, document.body);
        });
      });
    });
    

    Inside your App component (or any component in the hierarchy) you use this.props.children instead of <RouteHandler> to render your child route handler. This eliminates the need for <RouteHandler>, context hacks, and <DefaultRoute> since you can now choose to render something else by just checking this.props.children for truthiness.

    <NotFoundRoute> has also been removed in favor of just using <Route path="*">, which does the exact same thing.

    Non-JSX Config

    You can provide your route configuration using plain JavaScript objects; no JSX required. In fact, all we do is just strip the props from your JSX elements under the hood to get plain objects from them. So JSX is purely sugar API.

    var Router = createRouter(
      {
        component: App,
        childRoutes: [{
          name: 'home',
          component: Home
        }]
      }
    );
    

    Note the use of childRoutes instead of children above. If you need to load more route config asynchronously, you can provide a getChildRoutes(callback) method. For example, if you were using webpack's code splitting feature you could do:

    var Router = createRouter(
      {
        component: App,
        getChildRoutes(callback) {
          require.ensure([ './HomeRoute' ], function (require) {
            callback(null, [ require('./HomeRoute') ]); // args are error, childRoutes
          }
        }
      }
    );
    

    Which brings me to my next point ...

    Gradual Path Matching

    Since we want to be able to load route config on-demand, we can no longer match the deepest route first. Instead, we start at the top of the route hierarchy and traverse downwards until the entire path is consumed by a branch of routes. This works fine in most cases, but it makes it difficult for us to nest absolute paths, obviously.

    One solution that @ryanflorence proposed was to let parent routes essentially specify a function that would return true or false depending on whether or not that route thought it could match the path in some grandchild. So, e.g. you would have something like:

    var Router = createRouter(
      {
        path: '/home',
        component: Home,
        childRouteCanMatch(path) {
          return (/^\/users\/\d+$/).test(path);
        },
    
        // keep in mind, these may be loaded asynchronously
        childRoutes: [{
          path: '/users/:userID',
          component: UserProfile
        }]
      }
    );
    

    Now, if the path were something like /users/5 the router would know that it should load the child routes of Home because one of them probably matches the path. This hasn't been implemented yet, but I thought I'd mention it here for discussion's sake.

    Async Component Loading

    Along with on-demand loading of route config, you can also easily load components when they are needed.

    var Router = createRouter(
      {
        path: '/home',
        getComponents(callback) {
          require.ensure([ './Home' ], function (require) {
            callback(null, require('./Home')); // args are error, component(s)
          }
        }
      }
    );
    

    Rendering Multiple Components

    Routes may render a single component (most common) or multiple. Similar to ReactChildren, if components is a single component, this.props.children will be a single element. In order to render multiple components, components should be an object that is keyed with the name of a prop to use for that element.

    var App = React.createClass({
      render() {
        var { header, sidebar } = this.props;
        // ...
      }
    });
    
    var Router = createRouter(
      {
        path: '/home',
        component: App,
        childRoutes: [{
          path: 'news',
          components: { header: Header, sidebar: Sidebar }
        }]
      }
    );
    

    Note: When rendering multiple child components, this.props.children is null. Also, arrays as children are not allowed.

    Props

    Aside from children, route components also get a few other props:

    • location: the current Location (see below)
    • params: the URL params
    • route: the route object that is rendering that component

    Error/Update Handling

    The router also accepts onError and onUpdate callbacks that are called when there are errors or when the DOM is updated.

    History/Location API

    Everything that used to be named *Location is now called *History. A history object is a thing that emits Location objects as the user navigates around the page. A Location object is just a container for the path and the navigationType (i.e. push, replace, or pop).

    History objects are also much more powerful now. All have a go(n) implementation, and HTML5History and History (used mainly for testing) have reliable canGo(n) implementations.

    There is also a NativeHistory implementation that should work on React Native, tho it's a little tricky to get it working ATM.

    Transition Hooks

    The willTransitionTo and willTransitionFrom transition hooks have been removed in favor of more fine-grained hooks at both the route and component level. The transition hook signatures are now:

    • route.onLeave(router, nextState)
    • route.onEnter(router, nextState)

    Transition hooks still run from the leaf of the branch we're leaving, up to the common parent route, and back down to the leaf of the branch we're entering, in that order. Additionally, component instances may register hook functions that can be used to observe and/or prevent transitions when they need to using the new Transition mixin. Component instance-level hooks run before route hooks.

    var { Transition } = require('react-router');
    
    var MyComponent = React.createClass({
      mixins: [ Transition ],
      transitionHook(router) {
        if (this.refs.textInput.getValue() !== '' && prompt('Are you sure?'))
          router.cancelTransition();
      },
      componentDidMount() {
        this.addTransitionHook(this.transitionHook);
      },
      componentWillUnmount() {
        this.removeTransitionHook(this.transitionHook);
      },
      render() {
        return (
          <div>
            <input ref="textInput" type="text"/>
          </div>
        );
      }
    });
    

    Anyway, apologies for the long-winded PR, but there's a lot of stuff here! Please keep comments small and scoped to what we're doing here. I'd hate for this to turn into a huge thread :P

    Edit: Added data-loading example. Edit: Added transition hooks. Edit: Added props for named children, disallow arrays. Edit: Added addTransitionHook/removeTransitionHook API. Edit: Renamed Router.run => Router.match Edit: Removed static transition hooks

    Stuff we still need:

    Ok. Stuff we still need here:

    • [ ] Support absolute paths inside nested UI somehow in new path matching algorithm
    • [x] ~~Move routerWillLeave hook to instance lifecycle method instead of static~~ Add component-level API for observing/preventing transitions
    • [x] Add back scroll history support (@gaearon can you help w/ this?)
    • [ ] Maybe remove canGo(n) support (@taurose can you help determine if the current impl. is legit or not? if not, let's just remove it)

    COME ON! LET'S GET THIS MERGED AND SHIP 1.0!!!!

    opened by mjackson 141
  • RFC: Relative Links and Routes

    RFC: Relative Links and Routes

    We intend to ship Relative Routes and Relative Links soon. I'd like to hear people's comments on something I'm not totally sure about yet.

    What are Relative Links and Routes?

    Instead of <Route path={match.path + '/more/stuff'}/> you could simply do <Route path="more/stuff"/> and Router will use the lack of / at the start of your path as a hint that you want to just use whatever path is above you. Relative!

    Same with links. Instead of <Link to={match.url + '/more/stuff'}/> you can just do <Link to="more/stuff"/>.

    The Problem

    Going "down" as shown in the quick example up there is easy. But we're not sure what ".." should mean. There are two options for what it means: go up a URL segment, or go up a matched route.

    Go up a URL segment

    With plain anchors tags, .. means "up a URL segment". Given the following URL, an anchor tag with the following HREFs results in the following URLs:

    /clients/invoice/123
    

    href | url -----|----- payments | /clients/invoice/123/payments | /clients/invoice/123 . | /clients/invoice/123 .. | /clients/invoice ../ | /clients/invoice ../.. | /clients ../../ | /clients

    (As far as I can tell, feel free to double check!)

    So I think everybody's intuition around this is to just do exactly that and be done with it. Ship it.

    However, I have this gut instinct that our intuition right now might be keeping us from a better meaning of ".." in a React Router app?

    Go up a matched Route

    Maybe your app is something like this:

      <Switch>
        <Route exact path="/" component={Home}/>
        <Route path="/clients" render={() => (
          <Clients>
            <Switch>
              <Route exact path="." component={ClientList}/>
              <Route path="invoice/:invoiceId" component={Invoice}/>
            </Switch>
          </Clients>
        )}/>
      </Switch>
    

    Maybe we want ".." to mean "go up a matched route" rather than "go up some url segments".

    So now the "relative" portion of the Link's to prop is the parent Route's path, not the current location.

    to prop | link's url -----|----- .. | /clients ../.. | /

    Notice .. doesn't go to "invoice" because that's not a route that will ever match.

    Pros

    • When you change a parent Route's path prop, the relative links below don't need to be updated
    • You can't link to something that doesn't have UI (probably, see cons*)

    Cons

    • *Since any ol' route can match a location w/o a relationship with other Route's that match, a Link in one place can potentially have a completely different href than a link somewhere else--even though they have the same to prop 😬. It all depends on the Route's path the Link is rendered within.
    • It's against most people's intuition

    What do you think?

    opened by ryanflorence 116
  • [added] Router.renderRoutesToString

    [added] Router.renderRoutesToString

    This PR allows the path to be given to as a prop.

    <Routes initialPath="/some/path"> ... </Routes>
    

    This only works server side. This patch also stops the URLStore and RoutesStore being started as componentWillMount is called but componentWillUnmount isn't call on server side. This would lead to a memory leak and potential async issue when multiple pages are being rendered at once.

    When rendering on server side you should always make a new instance of <Routes> so if multiple pages are being rendered they don't change the routes in another page.

    var App = React.createClass({
      render: function(){
        return <Routes initialPath={this.props.initialPath} location="history"> ... </Routes>
      }
    });
    
    //server side
    React.renderComponentToString(<App initialPath="/some/path" />);
    
    //client side
    React.renderCompoent(<App />, domelement);
    
    opened by karlmikko 108
  • Proposal: Replace AsyncState with getAsyncProps

    Proposal: Replace AsyncState with getAsyncProps

    Edit: Please read my updated proposal as well

    I'd like to propose adding two new transition hooks, didTransitionTo and didTransitionFrom that are designed to replace the AsyncState mixin. Currently, AsyncState has the following quirks/limitations:

    • It keeps data in this.state, but data is passed passed to children through props in render
    • It's a mixin but it was only ever intended to be used in route handler components, so users may be inclined to use it in other components (which we don't support). Also, it means that users need to declare the mixin

    The goals for these two new transition hooks are:

    • Keep data in props, where it belongs. this.state should be used for UI state
    • Keep the ability for components to subscribe to changes in data, but also have a way to let components know that data only needs to be fetched once (for server rendering)
    • Keep the ability for components to fetch data in parallel
    • More clearly indicate that data fetching behavior belongs in route handlers, and not other components and eliminate the need for users to declare a mixin in order to use it

    I believe the following API satisfies all of the above requirements. Feedback is welcome.

    var User = React.createClass({
    
      statics: {
    
        // This hook is called after the transition has been validated by all
        // willTransition* hooks. The setProps argument is a function that
        // can be used to set props ad hoc (like AsyncState's setState).
        didTransitionTo: function (params, query, singleRun, setProps) {
          // If you have an immediate value, use it.
          setProps({ user: UserStore.getUserByID(params.userID) });
    
          // If we're not on the server, subscribe to changes in the data.
          if (!singleRun) {
            this.userListener = function () {
              setProps({ user: UserStore.getUserByID(params.userID) });
            };
    
            UserStore.addChangeListener(this.userListener);
          }
    
          // Or, ignore setProps entirely and return a hash of values that should
          // be used as props. Values may be immediate or promises. As they
          // resolve, props are updated.
          return {
            user: fetchUser(params.userID)
          };
        },
    
        // This hook is called after the transition has been validated by all
        // willTransition* hooks.
        didTransitionFrom: function () {
          UserStore.removeChangeListener(this.userListener);
        }
    
      },
    
      // The render method needs to be resilient to the fact that props
      // may not yet be loaded.
      render: function () {
        var user = this.props.user;
        var name = user == null ? 'anonymous' : user.name;
    
        return <div className="user-component">Hello {name}!</div>;
      }
    
    });
    

    Note that, although this API looks similar to the willTransition* API, it has two key differences:

    • handlers are run in parallel, not in sequence, so all data can be fetched at the same time
    • the resolution of these handlers does not block the transition from happening

    Thanks to @rpflorence for giving me feedback and helping me think through this API earlier today!

    Edit: Updated example code to make setProps the last (optional) argument to didTransitionTo.

    feature 
    opened by mjackson 107
  • v2 Roadmap

    v2 Roadmap

    This might not be the best way to manage this (one gigantic issue), but @mjackson and I are a solid 50% done with all of this anyway, so I'm not too concerned.

    @taion you'll likely have some questions since this affects a lot of what you're trying to do, please chat me up on discord before we clog up this issue with back-and-forth conversation :)

    Router 2.0 Roadmap

    TOC

    Motivations for the following API changes are all about cleaning up and clarifying the coupling between React Router and History; this generally translates to "You won't need to know anything about History anymore."

    • Learning the router is complicated by History, you have to learn both APIs and the line between them is unclear. This affects end users trying to use the libraries together as well as contributors (for example duplication of docs is also a problem).
    • We have some rough edges around ingration with libraries like React native, Redux, Relay, and our own AsyncProps.
    • React 15 is only going to allow components to export only one object to "context" (we only want one anyway)

    The following issues should help address these concerns.

    Note about upgrading

    All v1.0.0 APIs will continue to work in v2.0.0. An app using only public API should be able to drop in v2.0.0 and just get warnings. Old API will be removed in 3.0.0. If you update your code and no longer get warnings, you should be able to upgrade to 3.0 w/o trouble.

    Ship History 2.0

    It's really just removing deprecated API. The rest of these items all kind of depend on it though.

    Refactor route matching out of useRoutes and into match

    Background

    Currently we wrap a history with useRoutes so it is now aware of routes and performs the match against them. This changes the signature and timing of listen (making it async) causing difficulty when integrating or using alongside libraries like redux and react native.

    Additionally, navigating outside of components (like in flux and redux) is complicated by Router wrapping the history provided as a prop.

    Goals

    • Remove need for listenRoutes to integrate with other libs
    • Make navigating outside of components simpler for redux/flux etc.
    • Not require apps to wrap their singleton history in things like useQueries in order to navigate outside of components
    • apps can still learn about History and add behavior if they choose, (custom queryString parsing, etc.) and Router should not touch the history provided

    Upgrading

    ////////////////////////////////////////////////////////////////////////////////
    // Rendering
    // v1.0.0
    import createBrowserHistory from 'history/lib/createBrowserHistory'
    render(<Router history={createBrowserHistory()}/>, el)
    
    // v2.0.0
    import { browserHistory } from 'react-router'
    render(<Router history={browserHistory}/>, el)
    
    ////////////////////////////////////////////////////////////////////////////////
    // Navigating outside of components
    
    // v1.0.0
    // probably exported from a module somehwere like this
    import createBrowserHistory from 'history/lib/createBrowserHistory'
    import useQueries from 'history/lib/useQueries'
    const createHistory = useQueries(createBrowserHistory)
    export default createHistory()
    // and then used in an action or somehwere
    import appHistory from './appHistory'
    appHistory.push(...)
    
    // v2.0.0
    // React Router exports a singleton
    import { browserHistory } from 'react-router'
    browserHistory.push(...)
    

    Tasks

    While the nitty gritty won't be this simple, this is what will probably need to happen:

    • remove useRoutes and move all route matching to match
    • use match inside of Router instead of wrapping the history provided in anything (don't alter history)
    • create hashHistory and browserHistory singletons, exported from index.js
    • remove default to hashHistory and require devs to provide one, should help with people not understanding that there's a better option, and allow devs to decrease the bundle size of their app

    Export only router to context

    Background

    Right now we put history, location, and route (sometimes) on context, we also pass a bag of props to route components. Turns out there's some overlap between them. We're tempted to add more to context, and add more to props because the line and purpose between them isn't clear.

    React Router continues to strive to be just one library in a wonderful ecosystem of other libraries, prescribing strategies for data flow in an app is not our goal. We will put only what we absolutely need in context (which can be summed up with "what does Link need?). Everything else will go to route components as props. The opinions of the app can take over from there.

    Context was recently documented, so we no longer need the mixins to hide the context API. It's up to the app to decide if it wants to use context directly or continue to hide it with mixins or higher order components.

    Also, react 15 or 16 will only allow one contextType. We've been talking about only have one context type for a while. Now is the time.

    Finally, in the global effort to make History an implementation detail, we need to provide something else to navigate around in components.

    Goals

    • Make separation between what is on context v. route props clear, and remove overlap
    • Let apps decide how to get props the router gives them down the render tree
    • Remove need to learn History API

    Tasks

    • Deprecate all items on context: history, location, route

    • Add context.router that looks like this:

      router: shape({
        push: func,
        replace: func,
        isActive: func,
        addRouteLeaveHook: func
      })
      
    • Pass router as a prop to route components

    • Deprecate all mixins

    • Deprecate passing history to route components

    • proxy push/replace/isActive/addRouteLeaveHook to underlying history (so integration with a custom history will work)

    • automatically remove route leave hooks since we should know everything we need to know, so devs don't have to and there's no reason to leave them hanging around.

    Upgrading

    History methods

    In all cases where you once had a history for navigation, you now have a router with different methods.

    // v1.0.0
    history.pushState(state, path, query)
    history.replaceState(state, path, query)
    
    // v2.0.0
    router.push(path)
    router.push({ path, query, state }) // new "location descriptor"
    
    router.replace(path)
    router.replace({ path, query, state }) // new "location descriptor"
    

    Navigating in route components

    // v1.0.0
    class RouteComponent extends React.Component {
      someHandler() {
        this.props.history.pushState(...)
      }
    }
    
    // v2.0.0
    class RouteComponent extends React.Component {
      someHandler() {
        this.props.router.push(...)
      }
    }
    

    Navigating inside deeply nested components

    // v1.0.0
    const DeepComponent = React.createClass({
      mixins: [ History ],
    
      someHandler() {
        this.history.pushState(...)
      }
    }
    
    // v2.0.0
    // You have a couple options:
    // Use context directly (recommended)
    const DeepComponent = React.createClass({
      contextTypes: {
        router: object.isRequired
      },
    
      someHandler() {
        this.context.router.push(...)
      }
    }
    
    // create your own mixin:
    const RouterMixin = {
      contextTypes: {
        router: object.isRequired
      },
      componentWillMount() {
        this.router = this.context.router
      }
    }
    
    const DeepComponent = React.createClass({
      mixins: [ RouterMixin ],
      someHandler() {
        this.history.pushState(...)
      }
    }
    
    // use the singleton history you are using when the router was rendered,
    import { browserHistory } from 'react-router'
    
    const DeepComponent = React.createClass({
      someHandler() {
        browserHistory.push(...)
      }
    }
    

    Lifecycle Mixin with route components

    // v1.0.0
    const RouteComponent = React.createClass({
      mixins: [ Lifecycle ],
      routerWillLeave() {
        // ...
      }
    })
    
    // v2.0.0
    const RouteComponent = React.createClass({
      componentDidMount() {
        const { router, route } = this.props
        router.addRouteLeaveHook(route, this.routerWillLeave)
      }
    })
    
    // or make your own mixin, check it out in the next section
    

    Lifecycle Mixin with deep, non-route components

    // v1.0.0
    const DeepComponent = React.createClass({
      mixins: [ Lifecycle ],
      routerWillLeave() {
        // do stuff
      }
    })
    
    // v2.0.0
    // you have a couple of options
    // first you can put the route on context in the route component
    const RouteComponent = React.createClass({
      childContextTypes: {
        route: object
      },
    
      getChildContext() {
        return { route: this.props.route }
      }
    })
    
    // and then access it on your deep component
    const DeepComponent = React.createClass({
      contextTypes: {
        route: object.isRequired,
        router: objec.isRequired
      },
    
      componentDidMount() {
        const { router, route } = this.context
        router.addRouteLeaveHook(route, this.routerWillLeave)
      }
    })
    
    // or make your own mixin that will work for both route components and
    // deep components alike (as long as your route component puts `route`
    // on context
    const Lifecycle = {
      contextTypes: {
        route: object.isRequired,
        router: objec.isRequired
      },
    
      componentDidMount() {
        const router = this.context.router
        const route = this.props.route || this.context.route
        router.addRouteLeaveHook(route, this.routerWillLeave)
      }
    }
    

    Add render prop to Router, remove RoutingContext prop

    Background

    The functional composition of history is awesome, but we also need this kind of composition for React Router when it's time to render. While we can add some behavior into history we lack the necessary lifecycle hooks that components give us. Integrations also need all of the routing information in aggregate (like all the components and routes).

    Our current workaround is the RoutingContext prop, but that only lets us add one level of behavior. Consider an app that was built with Async Props, but now wants to iterate to using Relay, as well as add a new scroll restoring behavior. If each of these components used the RoutingContext prop API, they would all render a RoutingContext and therefore can't be used together.

    Goals

    • Allow integration for middleware components that need lifecycle hooks and the aggregate routing information
    • Allow multiple levels of behavior, not just one

    Upgrading

    // v1.0.0
    render(<Router RoutingContext={AsyncProps}/>, el)
    
    // v2.0.0
    render((
      <Router render={(props) => (
        <AsyncProps {...props} render={(props) => (
          <RoutingContext {...props} />
        )}/>
      )}/>
    ), el)
    
    // While that's more code, now we can do this:
    render((
      <Router render={(props) => (
        <AsyncProps {...props} render={(props) => (
          <RelayRoutes {...props} render={(props) => (
            <ScrollRestorer {...props} render={(props) => (
              <RoutingContext {...props} />
            )}/>
          )}/>
        )}/>
      )}/>
    ), el)
    

    Tasks

    • Remove RoutingContext prop, no need for deprecation warnings, it's undocumented and everybody we've told to try it got an earful of "we aren't sure about this thing yet"
    • Add render prop to Router
    • Add a default prop that just renders a RoutingContext
    • Write a document about how to write a middleware component (should continue to send down the props in a method called render

    Holy smokes that looks like a lot, it's really not too much, and we're feeling really good about it all.

    opened by ryanflorence 97
  • Allow transition hooks access to a context object you can specify when you create the router.

    Allow transition hooks access to a context object you can specify when you create the router.

    I've been trying to make an authentication mixin that can access the state in one of my flux stores but am not using singletons that I can make available to the static methods. Would it be alright to pass a context object through to the static willTransition hook methods to allow them access to arbitrary services you might need?

        var context = {...}
        Router.create({routes: routes, transitionContext: context})
    
        statics: {
          willTransitionTo: function(transition) {
             var loginState = transition.context.getStore(LoginStore).getState();
          }
        }
    
    opened by bobpace 96
  • Server rendering dynamic routes

    Server rendering dynamic routes

    I use server side rendering with some code splitting routes. It looks like OK on my server side with shim require.ensure. But I get the following warning on my client side:

    Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
     (client) ctid=".bqth22sav4"><noscript data-reacti
     (server) ctid=".bqth22sav4"><div data-reactid=
    

    Here is the main part of my client side codes:

    
    const store = createStore(getInitialState());
    const history = createHistory();
    const { pathname, search } = window.location;
    const location = createLocation(pathname + search);
    
    match({ routes, location }, (err, redirectLocation, renderProps) => {
        render(
            <Provider store={store}>
                <Router
                    {...renderProps}
                    history={history}
                />
            </Provider>,
            document.getElementById('mount')
        );
    });
    

    Regards.

    feature 
    opened by Cap32 95
  • React Native

    React Native

    Just tracking react native thoughts here. My assumptions are probably all wrong since 1) I don't know much about native dev and 2) I've spent 5 minutes with react native but:

    1. Looks like a component is mounted as the "top level" thing, the router listens to a location and then renders an app, so the basic usage is probably going to be slightly different, your top level component has route definitions and gets a url passed in as a prop or something.
    2. We need some sort of iOS Location and eventually an Android location, it'll probably be stored in memory and persisted to some sort of localStorage equivalent. When the app boots we look at the URI requesting the launch first, and then the localStorage (whatever it really is) second.

    Again, I have no idea what I'm talking about yet. ¯(º_o)/¯

    opened by ryanflorence 95
  • this.context.router is undefined

    this.context.router is undefined

    I just upgraded to react-router (and react) 0.13, and got rid of all the deprecated State mixins. Using this.context.router doesn't seem to work. I just see this everywhere:

    Uncaught TypeError: Cannot read property 'getParams' of undefined
    

    Is there anything additional I need to do?


    Edit by Ryan Florence to get people to the answer right here at the top of the issue :dancer:

    Check out the upgrade guide: https://github.com/rackt/react-router/blob/master/UPGRADE_GUIDE.md#012x---013x

    Sorry it wasn't done w/ the release, it's been an abnormally busy month for us since we quit our jobs and started a new business :P

    opened by tjwebb 94
  • ActiveState changes don't propagate if any single parent in hierarchy declares shouldComponentUpdate

    ActiveState changes don't propagate if any single parent in hierarchy declares shouldComponentUpdate

    If I have a component using ActiveState mixin and some of its parents declare shouldComponentUpdate, the child won't update when active state changes.

    This is not normal because usually parent's shouldComponentUpdate doesn't magically cut the child off updates. If child listens to some store and calls setState, it will be updated. But this is not the case with context.

    Even if parent's shouldComponentUpdate implementation takes nextContext into account, it won't even get nextContext if it doesn't declare contextTypes itself. So basically, for ActiveState to work in a project that heavily uses shallow-comparing shouldComponentUpdate or something similar, all ancestors of ActiveState-using component need to also have ActiveState.

    See this React issue and this fiddle.

    Obviously it's a React's problem per se but since router relies on context so much, it's worth documenting.

    bug 
    opened by gaearon 87
  • [Bug]: scroll reset to top when  fetcher.submit or submit from useSubmit

    [Bug]: scroll reset to top when fetcher.submit or submit from useSubmit

    What version of React Router are you using?

    6.6.1

    Steps to Reproduce

    Hi i startup new project with react-router v6.6.1, and i implement submit with useSubmit or fetcher.submit. (test both)

    when i submit, action doesn't redirect so same path is remaining, but when action is finish scroll position reseted.

    I also read official doc, issue and pr but i can't find fitting in.

    https://reactrouter.com/en/main/components/scroll-restoration i tried this but notting different.

    Expected Behavior

    After submit, action result arrived to useActionData and scroll position have to be remain

    Actual Behavior

    In the real world, scroll reset to top even it there is no page navigation or redirection

    bug 
    opened by whtjs 0
  • add createModuleRoutes() utility function for lazy loading route modules

    add createModuleRoutes() utility function for lazy loading route modules

    Discussion

    The createModuleRoutes() utility is inspired by the Remix Route module convention. It allows a dev to provide a module function on their route that dynamically imports a route module with named exports, instead of explicitly adding those properties to the Route object.

    That is to say, it turns this:

    import Foo, { fooLoader, fooAction, FooErrorBoundary } from './pages/foo';
    
    {
      path: "foo",
      element: <Foo />,
      loader: fooLoader,
      action: fooAction,
      errorElement: <FooErrorBoundary />,
    }
    

    into this:

    {
      path: "foo",
      module: () => import('./pages/foo'),
    }
    

    Any properties set directly on the route object take precedence over module exports. So if you have specific routes you want to not lazy load the loader so it can fetch data as fast as possible, you just specify loader directly on the route alongside the module, and that will be the loader that gets invoked (the implementation won't even both trying to set up a lazy-loaded loader in that case):

    {
      path: "foo",
      module: () => import('./pages/foo'),
      loader: fooLoader,
    }
    

    The same goes for action, element

    By leveraging import() and React.lazy() the implementation is super straightforward, and practically every build tool and bundler knows how to code-split when it sees that.

    I think this could be useful for a large number of React Router users by providing a "happy path" for code-splitting and lazy loading without being too heavy-handed.

    It can also serve as a foundation for file-based routing plugins for things like Webpack/Vite/Parcel/etc.

    This gives the developer a lever to pull between:

    • bundling all your loaders in the primary chunk for fastest possible execution of data fetching, at the cost of larger bundle sizes
    • lazily loading your loader/action code along with your UI component for smallest initial bundle size at the cost of additional latency when lazy loading the route module code
    • or any configuration in between

    Which I think is very much in the Remix spirit of things :) Feedback welcome!


    PS: I know I probably left out a bunch of stuff (docs/tests/etc), if this is something y'all are interested in merging I'll be sure to flesh out this PR with all those goodies. I also have next to zero experience with React Native, so not sure if this is something useful in that space either.

    CLA Signed 
    opened by rossipedia 6
  • Improved absolute redirect url detection in actions/loaders

    Improved absolute redirect url detection in actions/loaders

    This solves the issue remix-run/remix#5002.

    With this change, we are able to redirect to URI's like mailto:[email protected] before this change it was not possible because it was interpreted as a relative path.

    The regex comes from https://stackoverflow.com/a/31991870 and should match all common absolute URLs and URIs including string starting with //.

    I tested it with in my own project and it worked like a charm!

    CLA Signed 
    opened by lkwr 3
  • SSR in >= 6.4? (Documentation outdated)

    SSR in >= 6.4? (Documentation outdated)

    What is the new or updated feature that you are suggesting?

    Is or will it be possible to still Server Side Render in React Router >= 6.4?

    The documentation seems to be outdated at this moment (https://reactrouter.com/en/main/guides/ssr). The new RouterProvider/Router object does not seem to be compatible with the older 'StaticRouter'.

    Why should this feature be included?

    Not all the features of Remix might be needed, but it would still be nice to do a simple SSR, like we could in version <= 6.3.

    feature 
    opened by xriter 1
  • test(react-router-dom): streamline jsdom submitter bug workaround

    test(react-router-dom): streamline jsdom submitter bug workaround

    Work around the submitter bug in just one place, and link to my jsdom PR which will fix it, so that the workaround can be removed sooner rather than later 🤞

    This workaround refactor also establishes a pattern for other jsdom bug polyfills which will be landing in forthcoming RR PRs (the bugs aren't relevant in the current test suite, but will be in the PRs 😅)

    CLA Signed 
    opened by jenseng 4
  • [email protected](Dec 23, 2022)

  • [email protected](Dec 21, 2022)

    What's Changed

    This minor release is primarily to stabilize our SSR APIs for Data Routers now that we've wired up the new RouterProvider in Remix as part of the React Router-ing Remix work.

    Minor Changes

    • Remove unstable_ prefix from createStaticHandler/createStaticRouter/StaticRouterProvider (#9738)
    • Add useBeforeUnload() hook (#9664)

    Patch Changes

    • Support uppercase <Form method> and useSubmit method values (#9664)
    • Fix <button formmethod> form submission overriddes (#9664)
    • Fix explicit replace on submissions and PUSH on submission to new paths (#9734)
    • Prevent useLoaderData usage in errorElement (#9735)
    • Proper hydration of Error objects from StaticRouterProvider (#9664)
    • Skip initial scroll restoration for SSR apps with hydrationData (#9664)
    • Fix a few bugs where loader/action data wasn't properly cleared on errors (#9735)

    Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.6.0

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Dec 16, 2022)

    What's Changed

    This release introduces support for Optional Route Segments. Now, adding a ? to the end of any path segment will make that entire segment optional. This works for both static segments and dynamic parameters.

    Optional Params Examples

    • <Route path=":lang?/about> will match:
      • /:lang/about
      • /about
    • <Route path="/multistep/:widget1?/widget2?/widget3?"> will match:
      • /multistep
      • /multistep/:widget1
      • /multistep/:widget1/:widget2
      • /multistep/:widget1/:widget2/:widget3

    Optional Static Segment Example

    • <Route path="/home?"> will match:
      • /
      • /home
    • <Route path="/fr?/about"> will match:
      • /about
      • /fr/about

    Minor Changes

    • Allows optional routes and optional static segments (#9650)

    Patch Changes

    • Stop incorrectly matching on partial named parameters, i.e. <Route path="prefix-:param">, to align with how splat parameters work. If you were previously relying on this behavior then it's recommended to extract the static portion of the path at the useParams call site: (#9506)
    // Old behavior at URL /prefix-123
    <Route path="prefix-:id" element={<Comp /> }>
    
    function Comp() {
      let params = useParams(); // { id: '123' }
      let id = params.id; // "123"
      ...
    }
    
    // New behavior at URL /prefix-123
    <Route path=":id" element={<Comp /> }>
    
    function Comp() {
      let params = useParams(); // { id: 'prefix-123' }
      let id = params.id.replace(/^prefix-/, ''); // "123"
      ...
    }
    
    • Persist headers on loader request's after SSR document action request (#9721)
    • Fix requests sent to revalidating loaders so they reflect a GET request (#9660)
    • Fix issue with deeply nested optional segments (#9727)
    • GET forms now expose a submission on the loading navigation (#9695)
    • Fix error boundary tracking for multiple errors bubbling to the same boundary (#9702)

    Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.5.0

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Dec 7, 2022)

    What's Changed

    • Fix requests sent to revalidating loaders so they reflect a GET request (#9680)
    • Remove instanceof Response checks in favor of isResponse (#9690)
    • Fix URL creation in Cloudflare Pages or other non-browser-environments (#9682, #9689)
    • Add requestContext support to static handler query/queryRoute (#9696)
      • Note that the unstable API of queryRoute(path, routeId) has been changed to queryRoute(path, { routeId, requestContext })

    Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.4.5

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Nov 30, 2022)

    What's Changed

    • Throw an error if an action/loader function returns undefined as revalidations need to know whether the loader has previously been executed. undefined also causes issues during SSR stringification for hydration. You should always ensure your loader/action returns a value, and you may return null if you don't wish to return anything. (#9511)
    • Properly handle redirects to external domains (#9590, #9654)
    • Preserve the HTTP method on 307/308 redirects (#9597)
    • Support basename in static data routers (#9591)
    • Enhanced ErrorResponse bodies to contain more descriptive text in internal 403/404/405 scenarios
    • Fix issues with encoded characters in NavLink and descendant <Routes> (#9589, #9647)
    • Properly serialize/deserialize ErrorResponse instances when using built-in hydration (#9593)
    • Support basename in static data routers (#9591)
    • Updated dependencies:

    Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.4.4

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Nov 1, 2022)

    What's Changed

    • Generate correct <a href> values when using createHashRouter (#9409)
    • Better handle encoding/matching with special characters in URLs and route paths (#9477, #9496)
    • Generate correct formAction pathnames when an index route also has a path (#9486)
    • Respect relative=path prop on NavLink (#9453)
    • Fix NavLink behavior for root urls (#9497)
    • useRoutes should be able to return null when passing locationArg (#9485)
    • Fix initialEntries type in createMemoryRouter (#9498)
    • Support basename and relative routing in loader/action redirects (#9447)
    • Ignore pathless layout routes when looking for proper submission action function (#9455)
    • Add UMD build for @remix-run/router (#9446)
    • Fix createURL in local file execution in Firefox (#9464)

    New Contributors

    • @danielberndt made their first contribution in #9485
    • @AchThomas made their first contribution in #9464
    • @manzano78 made their first contribution in #9451

    Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.4.3

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Oct 6, 2022)

    What's Changed

    • Respect basename in useFormAction (#9352)
    • Fix IndexRouteObject and NonIndexRouteObject types to make hasErrorElement optional (#9394)
    • Enhance console error messages for invalid usage of data router hooks (#9311)
    • If an index route has children, it will result in a runtime error. We have strengthened our RouteObject/RouteProps types to surface the error in TypeScript. (#9366)

    Full Changelog: https://github.com/remix-run/react-router/compare/[email protected]@6.4.2

    Source code(tar.gz)
    Source code(zip)
  • v5.3.4(Oct 2, 2022)

    We removed the mini-create-react-context dependency, moving it into an internal module to eliminate peer dependency warnings for users on React 18 (#9382).

    Full Changelog: https://github.com/remix-run/react-router/compare/v5.3.3...v5.3.4

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Sep 22, 2022)

  • [email protected](Sep 13, 2022)

    Whoa this is a big one! 6.4.0 brings all the data loading and mutation APIs over from Remix. Here's a quick high level overview, but it's recommended you go check out the docs, especially the feature overview and the tutorial.

    New APIs

    • Create your router with createMemoryRouter
    • Render your router with <RouterProvider>
    • Load data with a Route loader and mutate with a Route action
    • Handle errors with Route errorElement
    • Defer non-critical data with defer and Await

    react-router-dom APIs

    • Create your router with createBrowserRouter/createHashRouter
    • Submit data with the new <Form> component
    • Perform in-page data loads and mutations with useFetcher()
    • Defer non-critical data with defer and Await
    • Manage scroll position with <ScrollRestoration>
    • Perform path-relative navigations with <Link relative="path"> (#9160)

    Bug Fixes

    • Path resolution is now trailing slash agnostic (#8861)
    • useLocation returns the scoped location inside a <Routes location> component (#9094)
    • Respect the <Link replace> prop if it is defined (#8779)
    Source code(tar.gz)
    Source code(zip)
  • @remix-run/[email protected](Sep 13, 2022)

    This is the first stable release of @remix-run/router, which provides all the underlying routing and data loading/mutation logic for react-router. You should not be using this package directly unless you are authoring a routing library similar to react-router.

    For an overview of the features provided by react-router, we recommend you go check out the docs, especially the feature overview and the tutorial.

    For an overview of the features provided by @remix-run/router, please check out the README.

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Sep 8, 2022)

    Patch Changes

    • fix: remove internal router singleton (#9227)

      This change removes the internal module-level routerSingleton we create and maintain inside our data routers since it was causing a number of headaches for non-simple use cases:

      • Unit tests are a pain because you need to find a way to reset the singleton in-between tests
        • Use use a _resetModuleScope singleton for our tests
        • ...but this isn't exposed to users who may want to do their own tests around our router
      • The JSX children <Route> objects cause non-intuitive behavior based on idiomatic react expectations
        • Conditional runtime <Route>'s won't get picked up
        • Adding new <Route>'s during local dev won't get picked up during HMR
        • Using external state in your elements doesn't work as one might expect (see #9225)

      Instead, we are going to lift the singleton out into user-land, so that they create the router singleton and manage it outside the react tree - which is what react 18 is encouraging with useSyncExternalStore anyways! This also means that since users create the router - there's no longer any difference in the rendering aspect for memory/browser/hash routers (which only impacts router/history creation) - so we can get rid of those and trim to a simple RouterProvider

      // Before
      function App() {
        <DataBrowserRouter>
          <Route path="/" element={<Layout />}>
            <Route index element={<Home />}>
          </Route>
        <DataBrowserRouter>
      }
      
      // After
      let router = createBrowserRouter([{
        path: "/",
        element: <Layout />,
        children: [{
          index: true,
          element: <Home />,
        }]
      }]);
      
      function App() {
        return <RouterProvider router={router} />
      }
      

      If folks still prefer the JSX notation, they can leverage createRoutesFromElements (aliased from createRoutesFromChildren since they are not "children" in this usage):

      let routes = createRoutesFromElements(
        <Route path="/" element={<Layout />}>
          <Route index element={<Home />}>
        </Route>
      );
      let router = createBrowserRouter(routes);
      
      function App() {
        return <RouterProvider router={router} />
      }
      

      And now they can also hook into HMR correctly for router disposal:

      if (import.meta.hot) {
        import.meta.hot.dispose(() => router.dispose());
      }
      

      And finally since <RouterProvider> accepts a router, it makes unit testing easer since you can create a fresh router with each test.

      Removed APIs

      • <DataMemoryRouter>
      • <DataBrowserRouter>
      • <DataHashRouter>
      • <DataRouterProvider>
      • <DataRouter>

      Modified APIs

      • createMemoryRouter/createBrowserRouter/createHashRouter used to live in @remix-run/router to prevent devs from needing to create their own history. These are now moved to react-router/react-router-dom and handle the RouteObject -> AgnosticRouteObject conversion.

      Added APIs

      • <RouterProvider>
      • createRoutesFromElements (alias of createRoutesFromChildren)
    • Updated dependencies

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Aug 31, 2022)

  • [email protected](Aug 2, 2022)

    Patch Changes

    • c3406eb9: fix: Rename <Deferred> to <Await> (#9095)

      • We are no longer replacing the Promise on loaderData with the value/error when it settles so it's now always a Promise.
      • To that end, we changed from <Deferred value={promise}> to <Await resolve={promise}> for clarity, and it also now supports using <Await> with raw promises from anywhere, not only those on loaderData from a defer() call.
        • Note that raw promises will not be automatically cancelled on interruptions so they are not recommended
      • The hooks are now useAsyncValue/useAsyncError
    • Updated dependencies

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Aug 2, 2022)

  • [email protected](Aug 2, 2022)

  • @remix-run/[email protected](Aug 2, 2022)

    Patch Changes

    • c3406eb9: fix: Rename <Deferred> to <Await> (#9095)

      • We are no longer replacing the Promise on loaderData with the value/error when it settles so it's now always a Promise.
      • To that end, we changed from <Deferred value={promise}> to <Await resolve={promise}> for clarity, and it also now supports using <Await> with raw promises from anywhere, not only those on loaderData from a defer() call.
        • Note that raw promises will not be automatically cancelled on interruptions so they are not recommended
      • The hooks are now useAsyncValue/useAsyncError
    Source code(tar.gz)
    Source code(zip)
  • [email protected](Jul 22, 2022)

    Patch Changes

    • feat: Deferred API Updates (#9070)

      • Removes <Suspense> from inside <Deferred>, requires users to render their own suspense boundaries
      • Updates Deferred to use a true error boundary to catch render errors as well as data errors
      • Support array and single promise usages
        • return deferred([ await critical(), lazy() ])
        • return deferred(lazy())
      • Remove Deferrable/ResolvedDeferrable in favor of raw Promise's and Awaited
      • Remove generics from useDeferredData until useLoaderData generic is decided in 6.5
    • Updated dependencies

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Jul 22, 2022)

  • [email protected](Jul 22, 2022)

    Patch Changes

    • SSR Updates for React Router (#9058)

      Note: The Data-Router SSR aspects of @remix-run/router and react-router-dom are being released as unstable in this release (unstable_createStaticHandler and unstable_DataStaticRouter), and we plan to finalize them in a subsequent minor release once the kinks can be worked out with the Remix integration. To that end, they are available for use, but are subject to breaking changes in the next minor release.

      • Remove useRenderDataRouter() in favor of <DataRouterProvider>/<DataRouter>
      • Support automatic hydration in <DataStaticRouter>/<DataBrowserRouter>/<DataHashRouter>
        • Uses window.__staticRouterHydrationData
        • Can be disabled on the server via <DataStaticRouter hydrate={false}>
        • Can be disabled (or overridden) in the browser by passing hydrationData to <DataBrowserRouter>/<DataHashRouter>
      • <DataStaticRouter> now tracks it's own SSR error boundaries on StaticHandlerContext
      • StaticHandlerContext now exposes statusCode/loaderHeaders/actionHeaders
      • foundMissingHydrationData check removed since Remix routes may have loaders (for modules) that don't return data for loaderData
    • Updated dependencies

    Source code(tar.gz)
    Source code(zip)
  • @remix-run/[email protected](Jul 22, 2022)

    Patch Changes

    • feat: Deferred API Updates (#9070)

      • Support array and single promise usages
        • return deferred([ await critical(), lazy() ])
        • return deferred(lazy())
      • Remove Deferrable/ResolvedDeferrable in favor of raw Promise's and Awaited
      • Remove generics from useDeferredData until useLoaderData generic is decided in 6.5
    • feat: Add createStaticRouter for @remix-run/router SSR usage (#9013)

      Notable changes:

      • request is now the driving force inside the router utils, so that we can better handle Request instances coming form the server (as opposed to string and Path instances coming from the client)
      • Removed the signal param from loader and action functions in favor of request.signal

      Example usage (Document Requests):

      // Create a static handler
      let { query } = unstable_createStaticHandler(routes);
      
      // Perform a full-document query for the incoming Fetch Request.  This will
      // execute the appropriate action/loaders and return either the state or a
      // Fetch Response in the case of redirects.
      let state = await query(fetchRequest);
      
      // If we received a Fetch Response back, let our server runtime handle directly
      if (state instanceof Response) {
        throw state;
      }
      
      // Otherwise, render our application providing the data routes and state
      let html = ReactDOMServer.renderToString(
        <React.StrictMode>
          <DataStaticRouter routes={routes} state={state} />
        </React.StrictMode>
      );
      

      Example usage (Data Requests):

      // Create a static route handler
      let { queryRoute } = unstable_createStaticHandler(routes);
      
      // Perform a single-route query for the incoming Fetch Request.  This will
      // execute the appropriate singular action/loader and return either the raw
      // data or a Fetch Response
      let data = await queryRoute(fetchRequest);
      
      // If we received a Fetch Response back, return it directly
      if (data instanceof Response) {
        return data;
      }
      
      // Otherwise, construct a Response from the raw data (assuming json here)
      return new Response(JSON.stringify(data), {
        headers: {
          "Content-Type": "application/json; charset=utf-8",
        },
      });
      
    • feat: SSR Updates for React Router (#9058)

      Note: The Data-Router SSR aspects of @remix-run/router and react-router-dom are being released as unstable in this release (unstable_createStaticHandler and unstable_DataStaticRouter), and we plan to finalize them in a subsequent minor release once the kinks can be worked out with the Remix integration. To that end, they are available for use, but are subject to breaking changes in the next minor release.

      • Remove useRenderDataRouter() in favor of <DataRouterProvider>/<DataRouter>
      • Support automatic hydration in <DataStaticRouter>/<DataBrowserRouter>/<DataHashRouter>
        • Uses window.__staticRouterHydrationData
        • Can be disabled on the server via <DataStaticRouter hydrate={false}>
        • Can be disabled (or overridden) in the browser by passing hydrationData to <DataBrowserRouter>/<DataHashRouter>
      • <DataStaticRouter> now tracks it's own SSR error boundaries on StaticHandlerContext
      • StaticHandlerContext now exposes statusCode/loaderHeaders/actionHeaders
      • foundMissingHydrationData check removed since Remix routes may have loaders (for modules) that don't return data for loaderData
    Source code(tar.gz)
    Source code(zip)
  • [email protected](Jul 14, 2022)

    Patch Changes

    • Feat: adds deferred support to data routers (#9002)

      Returning a deferred from a loader allows you to separate critical loader data that you want to wait for prior to rendering the destination page from non-critical data that you are OK to show a spinner for until it loads.

      // In your route loader, return a deferred() and choose per-key whether to
      // await the promise or not.  As soon as the awaited promises resolve, the
      // page will be rendered.
      function loader() {
        return deferred({
          critical: await getCriticalData(),
          lazy: getLazyData(),
        });
      };
      
      // In your route element, grab the values from useLoaderData and render them
      // with <Deferred>
      function DeferredPage() {
        let data = useLoaderData();
        return (
          <>
            <p>Critical Data: {data.critical}</p>
            <Deferred
              value={data.lazy}
              fallback={<p>Loading...</p>}
              errorElement={<RenderDeferredError />}>
              <RenderDeferredData />
            </Deferred>
          </>
        );
      }
      
      // Use separate components to render the data once it resolves, and access it
      // via the useDeferredData hook
      function RenderDeferredData() {
        let data = useDeferredData();
        return <p>Lazy: {data}</p>;
      }
      
      function RenderDeferredError() {
        let data = useRouteError();
        return <p>Error! {data.message} {data.stack}</p>;
      }
      

      If you want to skip the separate components, you can use the Render Props pattern and handle the rendering of the deferred data inline:

      function DeferredPage() {
        let data = useLoaderData();
        return (
          <>
            <p>Critical Data: {data.critical}</p>
            <Deferred value={data.lazy} fallback={<p>Loading...</p>}>
              {(data) => <p>{data}</p>}
            </Deferred>
          </>
        );
      }
      
    • feat: add basename support for data routers (#9026)

    • fix: Fix trailing slash behavior on pathless routing when using a basename (#9045)

    • Updated dependencies

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Jul 14, 2022)

  • [email protected](Jul 14, 2022)

  • @remix-run/[email protected](Jul 14, 2022)

    Patch Changes

    • fix: Handle fetcher 404s as normal boundary errors (#9015)
    • feat: adds deferred support to data routers (#9002)
    • feat: add basename support for data routers (#9026)
    • ci: simplify dist/ directory for CJS/ESM only (#9017)
    • fix: Fix trailing slash behavior on pathless routing when using a basename (#9045)
    Source code(tar.gz)
    Source code(zip)
  • [email protected](Jun 22, 2022)

    Patch Changes

    • fix: Make path resolution trailing slash agnostic (#8861)
    • fix: Additional logic fixed for relative navigation from index/pathless layout routes (#8985)
    • fix: export ActionFunctionArgs/LoaderFunctionArgs up through router packages (#8975)
    • Updated dependencies
    Source code(tar.gz)
    Source code(zip)
Declarative routing for React

React Router Declarative routing for React Docs View the docs here Migrating from 2.x/3.x? 3.x docs 2.x docs Packages This repository is a monorepo th

React Training 49.2k Dec 27, 2022
Declarative routing for React

Welcome to React Router · React Router is a lightweight, fully-featured routing library for the React JavaScript library. React Router runs everywhere

Remix 49.3k Jan 9, 2023
reach - Next Generation Routing for React

Next Generation Routing for React Documentation Documentation Site You can also find the docs in the website directory. Community Join us on Spectrum

Reach 6.9k Jan 7, 2023
🥢 A minimalist-friendly ~1.3KB routing for React and Preact. Nothing else but HOOKS.

wouter is a tiny router for modern React and Preact apps that relies on Hooks. A router you wanted so bad in your project! Features Zero dependency, o

Alexey Taktarov 4.8k Jan 4, 2023
VSCode extension to generate a router based on file based routing and nested layouts

vscode-router-generator VSCode Extension to generate a router based on a file structure and returning the correct nested layouts. There can be optiona

Rody Davis 8 Sep 29, 2022
Declarative router component for React.

React Router Component Version Compatibility >= 0.39.0 React v15,16 >= 0.32.0 React v15 >= 0.27.0 React 0.14 0.24 - 0.26.0 React 0.13 0.23 - 0.26.0 Re

Samuel Reed 871 Nov 29, 2022
Render isomorphic React + React Router apps and components in Node

Render isomorphic React + React Router apps and components in Node

Sequence Media 3 Nov 1, 2022
named routes for react-router and your react application

react-router-namesake Example import { Switch } from "react-router"; import { BrowserRouter, Route, Link } from "react-router-dom"; import { Router as

Joe Hsu 6 Aug 12, 2021
Frontend of agro rent app built with React, Axios, React-router-dom v6 & Bootstrap

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: ya

Anuj Sharma 1 Dec 8, 2021
React app with TypeScript - React Router Dom

React Project with - React Router Dom My name is Alex Principe. I'm a Full stack developer who shares programming code with the community. This repo c

Alex Principe 2 Sep 20, 2022
You can found the concept of react hooks, local storage, conditional rendering and react-router-dom.

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

Tikaram Acharya 2 Jun 1, 2022
Upschool-react-assignment - Dummy Amazon clone with Bootstrap and React

Dummy Amazon Clone with React - NozamA ?? In this assignment, I tried to build a

Merve Karabulut 12 May 13, 2022
a more intuitive way of defining private, public and common routes for react applications using react-router-dom v6

auth-react-router is a wrapper over react-router-dom v6 that provides a simple API for configuring public, private and common routes (React suspense r

Pasecinic Nichita 12 Dec 3, 2022
Automatic breadcrumbs for React-Router

React Breadcrumbs React component use to generate a breadcrumb trail (compatible with React Router). Installation npm install --save react-breadcrumbs

Sven Anders Robbestad 409 Dec 9, 2022
React Router scroll management

react-router-scroll React Router scroll management. react-router-scroll is a React Router middleware that adds scroll management using scroll-behavior

Jimmy Jia 846 Dec 18, 2022
:tada: Redux First History - Redux history binding support react-router - @reach/router - wouter

redux-first-history Redux First History - Make Redux 100% SINGLE-AND-ONLY source of truth! Redux history binding for react-router @reach/router wouter

Salvatore Ravidà 367 Dec 31, 2022
Redux bindings for React Router – keep your router state inside your Redux store

redux-router This project is experimental. For bindings for React Router 1.x see here In most cases, you don’t need any library to bridge Redux and Re

Andrew Clark 2.3k Dec 7, 2022
🔼 UI-Router for React

UI-Router provides extremely flexible, state based routing to the React ecosystem.

UI-Router 444 Dec 22, 2022
Easy Router for Effector with React bindings

effector-easy-router A declarative router for effector and react. It is inspired by react-router-dom and effector gates. Routes are independent from e

Kirill Kubryakov 10 Oct 7, 2022