SilverNak
SilverNak

Reputation: 3381

React Router does not render Component

I want to create a React app with a login. To maintain the user state, I want to use the Context API introduced with React 16.3. When implementing the login-routing, I followed the example in React Router documentation.

The source code below is (as I hope) a very simplified minimal example of my problem. When I open localhost:3000/protected in a browser, the URL changes correctly to localhost:3000/login, but the component is not shown. The render() method seems not to be called.

How can I persuade React to render my Login component?

Here is my source code.

App.js

import React, {Component} from 'react';
import {
    BrowserRouter as Router,
    Route
} from 'react-router-dom'
import Login from "./Login";
import Protected from "./Protected";
import ProtectedRoute from "./ProtectedRoute";
import UserContext from "./UserContext";

export default class App extends Component {
    render() {
        return (
            <Router>
                <UserContext.Provider value={false}>
                    <div>
                        <ProtectedRoute path='/protected' component={Protected}/>
                        <Route path='/login' component={Login}/>
                    </div>
                </UserContext.Provider>
            </Router>
        );
    }
}

Login.js

import React from 'react';

export default class Login extends React.Component {
    render() {
        return <p>Login</p>;
    }
}

UserContext.js

import React from "react";
const UserContext = React.createContext();
export default UserContext;

ProtectedRoute.js

import React from 'react'
import {Redirect, Route} from "react-router-dom";
import UserContext from './UserContext';

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

export default ProtectedRoute;

Protected.js

import React from 'react';

export default class Protected extends React.Component {
    render () {
        return <h2>protected</h2>;
    }
}

Upvotes: 5

Views: 1591

Answers (1)

Oblosys
Oblosys

Reputation: 15126

Looks like this is a bug: https://github.com/ReactTraining/react-router/issues/6072, and possibly even a React bug: https://github.com/facebook/react/issues/12551.

For now, you can get around it by rendering Router and your context provider in separate components. Like this, for example:

const Routes = () => (
  <UserContext.Provider value={false}>
      <div>
          <ProtectedRoute path='/protected' component={Protected}/>
          <Route path='/login' component={Login}/>
      </div>
  </UserContext.Provider>
);

export default class App extends Component {
    render() {
        return (
            <Router>
              <Routes/>
            </Router>
        );
    }
}

Upvotes: 2

Related Questions