简体   繁体   中英

Page not rendering; When passing props to children using protected routes in react-router-dom

I am trying to create protected routes with react-router-dom.

Strangely the error is saying:

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

Check the render method of Context.Consumer .

And this is the stack trace—what's strange is the error about expecting a string? Aren't I passing "/profile" in history.push ??

外

The reason I said that's strange is because in the console from dev-tools I am getting this:

index.js:1 Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: <Connect(withRouter(LinkNavWithLayout)) />. Did you accidentally export a JSX literal instead of a component?
    in Route (created by PrivateRoute)
    in PrivateRoute (created by App)
    in Switch (created by App)
    in App (created by Context.Consumer)
    in withRouter(App) (created by Connect(withRouter(App)))
    in Connect(withRouter(App)) (created by MyApp)
    in Container (created by MyApp)
    in PersistGate (created by MyApp)
    in Provider (created by MyApp)
    in MyApp (created by AppWithReactRouter)
    in Router (created by BrowserRouter)
    in BrowserRouter (created by AppWithReactRouter)
    in AppWithReactRouter (created by AppWithRedux)
    in AppWithRedux
    in Suspense (created by AppContainer)
    in Container (created by AppContainer)
    in AppContainer

To me that makes more sense as I feel the problem is in the Protected route component ie meaning the logic in my protected routes function or the way I am using it...

  const PrivateRoute = ({ component: Component, children, ...rest }) => (
   <Route {...rest} render={props => {
    console.log("In PrivateRoute isLoggedIn ", isLoggedIn);
    return isLoggedIn === true
    ? <Component {...props} >{children}</Component>
    : <Redirect to='/' />
   }} />
  )

And this is how I am using it.

return (
    <>
    <Switch>
     <Route
      path='/'
      exact
      render={(props) => <LinkNavWithLayout {...props} data={navBars}><Index {...props} /></LinkNavWithLayout>} />

     <Route
      path='/login'
      render={(props) => <Login {...props} />}
     />

     <Route
      path='/register'
      render={(props) => <Register {...props} />}
     />

     <PrivateRoute
      path='/profile'
      isLoggedIn={isLoggedIn}
      component={
       <LinkNavWithLayout data={navBars}><Profile /></LinkNavWithLayout>
      }
     />

     <PrivateRoute
      path='/dashboard'
      isLoggedIn={isLoggedIn}
      component={
       <LinkNavWithLayout data={navBars}><Dashboard /></LinkNavWithLayout>
      }
     />
     {/* <Route component={()=> <h1>Not found</h1>} /> */}
    </Switch>
    </>
  )
 }

So why is my page not rendering at all and what do the two errors have to do with one another? Any help will be appreciated!

UPDATE

I added fosso's suggestion...

const PrivateRoute = ({ component, isLoggedIn, ...rest }) => (
   <Route {...rest} render={props => {
    console.log("In PrivateRoute isLoggedIn ", isLoggedIn);
    return isLoggedIn === true
     ? { component }
     : <Redirect to='/' />
   }} />
  )

  return (
    <>
    <Switch>
     <Route
      path='/'
      exact
      render={(props) => <LinkNavWithLayout {...props} data={navBars}><Index {...props} /></LinkNavWithLayout>} />

     <Route
      path='/login'
      render={(props) => <Login {...props} />}
     />

     <Route
      path='/register'
      render={(props) => <Register {...props} />}
     />

     <PrivateRoute
      path='/profile'
      isLoggedIn={isLoggedIn}
      component={({ children }) => ( // not sure where you're planning on passing `children` from `PrivateRoute`
       <LinkNavWithLayout data={navBars}><Profile /></LinkNavWithLayout>
      )}
     />

     <PrivateRoute
      path='/dashboard'
      isLoggedIn={isLoggedIn}
      component={({children}) => ( // not sure where you're planning on passing `children` from `PrivateRoute`
       <LinkNavWithLayout data={navBars}><Dashboard /></LinkNavWithLayout>
      )}
   />
     {/* <Route component={()=> <h1>Not found</h1>} /> */}
    </Switch>
    </>
  )
 }
}

But now getting the following error:

Objects are not valid as a React child (found: object with keys {component}). If you meant to render a collection of children, use an array instead.
    in Route (created by PrivateRoute)
    in PrivateRoute (created by App)
    in Switch (created by App)
    in App (created by Context.Consumer)
    in withRouter(App) (created by Connect(withRouter(App)))
    in Connect(withRouter(App)) (created by MyApp)
    in Container (created by MyApp)
    in PersistGate (created by MyApp)
    in Provider (created by MyApp)
    in MyApp (created by AppWithReactRouter)
    in Router (created by BrowserRouter)
    in BrowserRouter (created by AppWithReactRouter)
    in AppWithReactRouter (created by AppWithRedux)
    in AppWithRedux
    in Suspense (created by AppContainer)
    in Container (created by AppContainer)
    in AppContainer
▶ 30 stack frames were collapsed.
callback

And still pointing to...

在此处输入图像描述

I see a few issues.

component needs to be a function, in your case you're passing a React element.

In your case, this might work:

<PrivateRoute
   path='/dashboard'
   isLoggedIn={isLoggedIn}
   component={({children}) => ( // not sure where you're planning on passing `children` from `PrivateRoute`
    <LinkNavWithLayout data={navBars}><Dashboard /></LinkNavWithLayout>
   )}
/>

As an alternative, you have to change the PrivateRoute component

const PrivateRoute = ({ component, isLoggedIn, ...rest }) => (
 <Route {...rest} render={props => {
  console.log("In PrivateRoute isLoggedIn ", isLoggedIn);
  return isLoggedIn === true
  ? {component}
  : <Redirect to='/' />
 }} />
  )

But you really should have it as a separate component.

In the second example, you would be instantiating the JSX from the parent, which might not be ideal. In the first case, component is generated at each re-render, which might not be necessary.

EDIT: full example

const {
  HashRouter,
  Switch,
  Route,
  Link
} = ReactRouterDOM

const Page2 = () => (
  <div>
    <h1>Page2</h1>
  </div>
)

const Page1 = () => (
  <div>
    <h1>Page1</h1>
  </div>
)

const Home = () => (
  <div>
    <h1>Home</h1>
  </div>
)

const PrivateRoute = ({component: Component, isLoggedIn, ...rest}) => (<Route {...rest} render={props => isLoggedIn ? <Component /> : <div>Not logged in</div>} />)

const Content = () => (
  <main>
    <Switch>
      <Route exact path='/' component={Home}/>
      <PrivateRoute path='/page1' isLoggedIn component={Page1}/>
      <PrivateRoute path='/page2' isLoggedIn={false} component={Page2}/>
    </Switch>
  </main>
)

const Nav = () => (
  <header>
    <nav>
      <ul>
        <li><Link to='/'>Home</Link></li>
        <li><Link to='/page1'>Page 1 (logged in)</Link></li>
        <li><Link to='/page2'>Page 2 (not logged in)</Link></li>
      </ul>
    </nav>
  </header>
)

const App = () => (
  <div>
    <Nav />
    <Content />
  </div>
)

ReactDOM.render((
  <HashRouter>
    <App />
  </HashRouter>
), document.getElementById('root'))

Tested in a codepen. Sorry, but if there are more errors I don't think I have enough information to debug further. I'd recommend posting another question with a full example.

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