React-router: Required prop was not specified. Check the render method of `RouterContext`.

Created on 11 Feb 2016  路  1Comment  路  Source: ReactTraining/react-router

Hey everyone,

Running into a warning on React-Router v2 (was also present on RC5, where I started, and RC6 as well) where we get the following error for -some- children components of layouts:

Required prop propName was not specified in ComponentName. Check the render method of RouterContext.

     import {Router, Route, Redirect, useRouterHistory } from 'react-router';
     import {createHashHistory} from 'history';

     const createAppHistory = useRouterHistory(createHashHistory);
     const appHistory = createAppHistory({
        queryKey : false,
        parseQueryString(queryString) {
          return qs.parse(queryString);
        },
        stringifyQuery(query) {
          return qs.stringify(query, { arrayFormat : 'brackets' });
        },
     });

    return (
      <Router history={appHistory}>
        <Route component={AppLayout}>
          <Route component={HomeLayout}>
            <Route path='/homes/:homeId' component={HomeOverview} />
            <Route path='/homes/:homeId/residents' component={HomeResidents} />
            <Route path='/homes/:homeId/devices' component={HomeDevices} />
          </Route>
       </Route>
     </Router>
   );

What's strange is that HomeOverview, HomeResidents, and Devices all have this.props.home as a required propType but only HomeResidents throws the aforementioned error.

I saw in the v2.0 examples that the layout usually has a path, so I gave mine a path of home and stripped that from the children components in another test but that didn't fix the issue so I reverted that change for now.

HomeLayout looks like this:

  render() {
    if (this.state.loading) {
      return <Loading />;
    } else if (! this.state.home) {
      return <HomeNotFound />;
    }

    return (
      <Page nav={<HomeTabs home={this.state.home} />}>
        {React.cloneElement(this.props.children, { home : this.state.home})}
      </Page>
    );
  },

The warning is triggered when ReactDOM renders the Router before my top level layout's (the navbar/footer, etc) render function is loaded.

Stack trace:

warning @   warning.js:45
checkPropTypes  @   ReactElementValidator.js:189
validatePropTypes   @   ReactElementValidator.js:208
ReactElementValidator.createElement @   ReactElementValidator.js:242
createElement   @   RouterContext.js:88
(anonymous function)    @   RouterContext.js:142
render  @   RouterContext.js:104
ReactCompositeComponentMixin._renderValidatedComponentWithoutOwnerOrContext @   ReactCompositeComponent.js:587
ReactCompositeComponentMixin._renderValidatedComponent  @   ReactCompositeComponent.js:607
wrapper @   ReactPerf.js:66
ReactCompositeComponentMixin.mountComponent @   ReactCompositeComponent.js:220
wrapper @   ReactPerf.js:66
ReactReconciler.mountComponent  @   ReactReconciler.js:37
ReactCompositeComponentMixin.mountComponent @   ReactCompositeComponent.js:225
wrapper @   ReactPerf.js:66
ReactReconciler.mountComponent  @   ReactReconciler.js:37
ReactCompositeComponentMixin.mountComponent @   ReactCompositeComponent.js:225
wrapper @   ReactPerf.js:66
ReactReconciler.mountComponent  @   ReactReconciler.js:37
ReactCompositeComponentMixin.mountComponent @   ReactCompositeComponent.js:225
wrapper @   ReactPerf.js:66
ReactReconciler.mountComponent  @   ReactReconciler.js:37
mountComponentIntoNode  @   ReactMount.js:266
Mixin.perform   @   Transaction.js:136
batchedMountComponentIntoNode   @   ReactMount.js:282
Mixin.perform   @   Transaction.js:136
ReactDefaultBatchingStrategy.batchedUpdates @   ReactDefaultBatchingStrategy.js:62
batchedUpdates  @   ReactUpdates.js:94
ReactMount._renderNewRootComponent  @   ReactMount.js:476
wrapper @   ReactPerf.js:66
ReactMount._renderSubtreeIntoContainer  @   ReactMount.js:550
ReactMount.render   @   ReactMount.js:570
wrapper @   ReactPerf.js:66
startApplication    @   main.jsx:75
tryCatchReject  @   makePromise.js:840
runContinuation1    @   makePromise.js:799
Fulfilled.when  @   makePromise.js:590
Pending.run @   makePromise.js:481
Scheduler._drain    @   Scheduler.js:62
Scheduler.drain @   Scheduler.js:27
Item.run    @   browser.js:64
drainQueue  @   browser.js:34

This isn't affecting us negatively in any way except that we see the warning, everything works as expected once the Components mount.

Apologies if this isn't a bug but an implementation error, in which case I can take the question to stack overflow or discord, but it seems like required proptypes shouldn't trigger errors before the component is mounted.

Most helpful comment

FWIW, that warning will go away in production builds.

This is because the router is creating an instance of your component, which fires off the PropTypes checks. Unfortunately, your route components can't have extra PropTypes, outside of the ones the router provides. cloneElement will check PropTypes on the cloned element, so that's why you won't see the message firing twice. I'm not sure why only some of the components are doing it.

One potential way around this is to provide your own createElement function, as you can use that to inject whatever props you want. It may be somewhat convoluted, though.

I don't think there's a definitive answer here. Given the way the router works with components, it does make working with PropTypes to be a little confusing. I would look at splitting out the route component from the presentational stuff. You don't want to start building huge, monolithic components on your route tree, otherwise everything becomes highly coupled and very resistant to change. You can always break things into multiple components to keep intent obvious and implementation simple and easy to understand.

>All comments

FWIW, that warning will go away in production builds.

This is because the router is creating an instance of your component, which fires off the PropTypes checks. Unfortunately, your route components can't have extra PropTypes, outside of the ones the router provides. cloneElement will check PropTypes on the cloned element, so that's why you won't see the message firing twice. I'm not sure why only some of the components are doing it.

One potential way around this is to provide your own createElement function, as you can use that to inject whatever props you want. It may be somewhat convoluted, though.

I don't think there's a definitive answer here. Given the way the router works with components, it does make working with PropTypes to be a little confusing. I would look at splitting out the route component from the presentational stuff. You don't want to start building huge, monolithic components on your route tree, otherwise everything becomes highly coupled and very resistant to change. You can always break things into multiple components to keep intent obvious and implementation simple and easy to understand.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nicolashery picture nicolashery  路  3Comments

imWildCat picture imWildCat  路  3Comments

misterwilliam picture misterwilliam  路  3Comments

ackvf picture ackvf  路  3Comments

maier-stefan picture maier-stefan  路  3Comments