Search code examples
javascriptreactjsreact-routerredux-router

reactjs router not rendering components


I have reactjs setup with routes but my routing is not working. When I load the page it works but when I click on the links the URL changes but the component does not render. I tried to put as much as I can in the sandbox. load with URL/admin and click on logout etc.

https://codesandbox.io/s/o5430k7p4z

index

import React, { Component } from 'react'
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, combineReducers } from 'redux';
import { BrowserRouter, Route, browserHistory } from 'react-router-dom';
import promise from 'redux-promise';
import { createLogger } from 'redux-logger';

import App from './App'
import reducers from './reducers';

require("babel-core/register");
require("babel-polyfill");
import 'react-quill/dist/quill.snow.css'; // ES6

const logger = createLogger();
const initialState = {};

const createStoreWithMiddleware = applyMiddleware(promise)(createStore);

ReactDOM.render(
        <Provider store={createStoreWithMiddleware(reducers)}>
            <BrowserRouter>
                <App/>
            </BrowserRouter>
        </Provider>
        , document.getElementById('root'));

App

import React, { Component } from 'react'
import { Switch, Route } from 'react-router-dom';
import ReactGA from 'react-ga';
ReactGA.initialize('UA-101927425-1');
import { connect } from 'react-redux';
import { fetchActiveUser } from './actions/index';
import { bindActionCreators } from 'redux'; 
import {getHttpRequestJSON} from './components/HTTP.js'

import Header from './components/header';
import Logout from './components/logout';
import SideBar from './components/sidebar';
import HomeContent from './containers/home';
import Ldapuser from './components/ldapuser';
import Admin from './components/admin/admin';

function fireTracking() {
    ReactGA.pageview(window.location.pathname + window.location.search);
}

class App extends Component {

    constructor(props){
        super(props);
        this.state = {
            isGuest : false,
            isSupp : false,
            loading: true,
            version: '',

        };
    }

    initData = () => {
        let self = this;

        getHttpRequestJSON('/api/user/get/user/method/is/guest/format/json?quiet=1')
        .then((response) => {
            let isGuest = response.body.recordset.record.isGuest;
            if(isGuest){
                /*$(".logo").trigger('click');
                //$("#overlay").show();
                $('#modalIntro').modal('toggle');

                $("#modalIntro").on("hidden.bs.modal", function () {
                    $(".logo").trigger('click');
                });*/
            }

            self.props.isGuest = isGuest;
            self.props.loading = false;
            //self.props.version = response.header.version;
            self.setState({
                 loading : false,
                 version : response.header.version,
                 isGuest : isGuest
            });
        })
        .catch(error => { 
            console.log("Failed!", error);
            //$('#myModalError .modal-body').html(error);
            //$('#myModalError').modal('show');
        });

        getHttpRequestJSON('/api/user/get/user/method/is/supp/format/json?quiet=1')
        .then((response) => {
            self.setState({
                isSupp : response.body.recordset.record.isSupp
            });
        })
        .catch(error => { 
            console.log("Failed!", error);
            //$('#myModalError .modal-body').html(error);
            //$('#myModalError').modal('show');
        }); 
    }

    componentDidMount() {
        this.props.fetchActiveUser();
        this.initData();
    }

    render() {
        return (
            <div>
                <Header activeUser={this.props.activeUser} loading={this.state.loading} version={this.state.version} title={`Home`} />
                <SideBar />
                <main>
                <Switch>
                   <Route path='/index.html' render={()=><HomeContent activeUser={this.props.activeUser} isGuest={this.state.isGuest} isSupp={this.state.isSupp} />} />
                   <Route path='/home' render={()=><HomeContent activeUser={this.props.activeUser} isGuest={this.state.isGuest} isSupp={this.state.isSupp} />} />       
                   <Route path='/logout' component={Logout}/>
                   <Route path='/ldapuser' component={Ldapuser}/>                  
                   <Route path='/admin' render={()=><Admin isGuest={this.state.isGuest} isSupp={this.state.isSupp}/>} />
                 </Switch>
                 </main>
             </div>
        );
    }
}

//export default App;
function mapStateToProps(state) {
    if(state.activeUser.id > 0){                  
        ReactGA.set({ userId: state.activeUser.id });
    }
    // Whatever is returned will show up as props
    // inside of the component
    return {
        activeUser: state.activeUser
    };
}

// Anything returned from this function will end up as props
// on this container
function mapDispatchToProps(dispatch){
    // Whenever getUser is called, the result should be passed
    // to all our reducers
    return bindActionCreators({ fetchActiveUser }, dispatch);
}

//Promote component to a container - it needs to know
//about this new dispatch method, fetchActiveUser. Make it available
//as a prop
export default connect(mapStateToProps, mapDispatchToProps)(App);

Solution

  • The codesandbox is not working, but I think what is happening to you is a very common problem when using react-redux and react-router. The connect HOC of react-redux has a builtin SCU (shouldComponentUpdate), so for it to know to rerender is requires to receive new props. This can be done using the withRouter hoc of react-router. Simply wrap connect(..)(MyComponent) with withRouter(connect(..)(MyComponent)) or do it clean and use compose (from recomponse for example);

    const enhance = compose(
       withRouter,
       connect(mapStateToProps)
    )
    export default enhance(MyComponent)
    

    Make sure not to do it the other way around, because that does not work.