Leon Gaban
Leon Gaban

Reputation: 39018

React How to get Component to detect route change

I have 3 routes which render the same component<MainContainer/>, I want state to change inside those components based on the location.

Routes:

import React from 'react'
import { browserHistory, HashRouter, Route, Switch } from 'react-router-dom'

import { MainContainer } from '../containers'
import { LoginContainer } from '../containers'

const Routes = () => {
  return (
    <HashRouter history={ browserHistory }>
      <Switch>
        <Route exact={ true } path="/" component={ LoginContainer }/>
        <Route exact={ true } path="/dashboard" component={ MainContainer }/>
        <Route exact={ true } path="/dashboard/services" component={ MainContainer }/>
        <Route exact={ true } path="/dashboard/users" component={ MainContainer }/>
      </Switch>
    </HashRouter>
  );
}

export default Routes

The problem is that the componentDidMount only fires once, and does not fire again when the path is changed:

enter image description here

How would detecting the state of the route be achieved in React using the hashRouter?

Sidebar

import React from 'react'
import { withRouter } from 'react-router-dom'

class Sidebar extends React.Component {

  constructor(props) {
        super(props);
        this.state = {}
    this.navigate = this.navigate.bind(this);
    }

  navigate(path) {
    this.props.history.push(`/dashboard/${path}`);
  }

  render () {
    return (
      <aside className="sidebar">
        <div>
          <h1>Main</h1>
          <ul>
            <li onClick={ () => this.navigate('services')}>Services</li>
            <li onClick={ () => this.navigate('users')}>Users</li>
          </ul>
        </div>
      </aside>
    )
  }
}

export default withRouter(Sidebar)

MainContainer

import React, { Component } from 'react'
import { connect } from 'react-redux'
import store from '../../store'
import * as firebase from 'firebase'

// Components
import { Sidebar } from '../../components'
import { Header } from '../../components'

// Containers
import UserListContainer from '../Users/UserListContainer'
import Body from './Body'

// Actions
import { addCurrentUser, searchUser, usersService, servicesService } from '../../actions'

export class Main extends Component {
    constructor(props) {
        super(props);
    }

    componentDidMount() {
        firebase.auth().onAuthStateChanged((user) => {
      this.checkAuth();
    });
    }

    checkAuth() {
        const user = firebase.auth().currentUser;
        this.props.addCurrentUser(user.email);
    }

    render() {
        return (
            <main>
                <Header currentUser={ this.props.currentUser }/>
                <section className="main-body">
                    <Sidebar />
                    <Body service={this.props.service}/>
                </section>
            </main>
        )
    }
}

const mapStateToProps = (state) => {
    return {
        service: state.globalReducer.service,
        currentUser: state.globalReducer.currentUser
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        searchUser: (user) => { dispatch(searchUser(user)) },
        addCurrentUser: (user) => { dispatch(addCurrentUser(user)) },
        usersService: () => { dispatch(usersService()) },
        servicesService: () => { dispatch(servicesService()) }
    }
}

const MainContainer = Main;
export default connect(mapStateToProps, mapDispatchToProps)(MainContainer)

Upvotes: 4

Views: 3201

Answers (1)

Kyle Richardson
Kyle Richardson

Reputation: 5645

If you want to get your current path in a component that is wrapped with withRouter() you can use the location prop provided to the component by withRouter().

props.location.pathname is probably what you are interested in here.

EDIT:

Ok so your <MainContainer /> is not aware of location. It is not wrapped with withRouter(). Your <Sidebar /> is, but I don't see where you do anything on route changes with that information.

EDIT #2:

Once you your component is location aware, you can add a componentWillReceiveProps lifecycle method and see that you are getting those properties in your component. You can use these properties anywhere in your component.

componentWillReceiveProps( nextProps ) {
    const { location, history, match } = this.props;

    console.log( location );
    console.log( history );
    console.log( match );
}

Upvotes: 4

Related Questions