简体   繁体   中英

React router private route not rendering

I'm trying to set up protected routes using react router v4.

I have the following, which works fine.

function PrivateRoute({ component: Component, authed, ...rest }) {
  return (
    <Route
      {...rest}
      render={props =>
        authed === true ? (
          <Component {...props} />
        ) : (
          <Redirect to={{ pathname: '/', state: { from: props.location } }} />
        )
      }
    />
  );
}

However, when I change this code to:

type PrivateRouteProps = {
  component: Component,
};

const PrivateRoute = ({ component, authed, ...rest }: PrivateRouteProps) => (
  <Route
    {...rest}
    render={props =>
      authed === true ? (
        <Component {...props} />
      ) : (
        <Redirect to={{ pathname: '/', state: { from: props.location } }} />
      )
    }
  />
);

I get the error: TypeError: instance.render is not a function . When I change to (note the component: Component ), everything works:

const PrivateRoute = ({ component: Component, authed, ...rest }) => (
  <Route
    {...rest}
    render={props =>
      authed === true ? (
        <Component {...props} />
      ) : (
        <Redirect to={{ pathname: '/', state: { from: props.location } }} />
      )
    }
  />
);

The render function of App.js is as follows:

render() {
    return this.state.loading === true ? (
      'loading'
    ) : (
      <BrowserRouter>
        <div>
          {this.renderHeader()}
          <Switch>
            <Route exact path="/" component={LandingPage} />
            <PrivateRoute
              authed={this.state.authed}
              path="/home"
              component={HomePage}
            />
            <Route component={PageNotFoundPage} />
          </Switch>
        </div>
      </BrowserRouter>
    );
  }

Why does the arrow function with PrivateRouteProps not work as expected?

In your second example you try to render the component you passed in with

<Component {...props}/>

From the way you defined your flow type I guess that you imported Component like this:

import React, {Component} from 'react'.

That means that Component does not refer to the component passed in the component prop but still to the class Component imported from react because you did not shadow it anywhere inside your functional component. Even if you imported Component in your first example it would still work because you shadowed the name Component with the value of the prop component . In the second example you did not do that.

This is why you get the error because the react class Component neither has a render() method nor does it have any other functionality you expected there.

You need to assign the prop component to another name that is capitalized, eg Node and then render that variable. Note that the name needs to be capitalized. Otherwise it will be interpreted as usual html node and not as a react component:

type PrivateRouteProps = {
  component: Component,
};

const PrivateRoute = ({ component: Node /* assign it to a capitalized name */, authed, ...rest }: PrivateRouteProps) => (
  <Route
    {...rest}
    render={props =>
      authed === true ? (
        {/* Do not use `Component` here as it refers to the class imported from react and not to your component */}
        <Node {...props} />
      ) : (
        <Redirect to={{ pathname: '/', state: { from: props.location } }} />
      )
    }
  />
);

You could of course also use Component as a name which will shadow the name Component from the outer scope but this is bad practice as it often leads to confusion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM