Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using connect() from react-redux makes NavLinks from react-router not work?

I'm learning redux and created a Navbar component that will handle user actions. It uses NavLink to add the 'active' class to my links so I can style the active link. When I navigate my site however the active class doesn't move until I send an action to react (login/logout is all I"ve done so far). If I take out the connect stuff and use the class component directly the NavLinks work fine. Adding a log to componentDidUpdate shows that it isn't being called when connect is used.

Am I missing something? I see there's react-router-redux but I'm building a site for fun to learn the whole deal and I'm just starting to get redux, I don't want to bring in the concept of middleware and I definitely don't want to use combineReducers since at this point it would just mean having the router property and shoving everything else under something like 'main' in the state.

I'm thinking of using context and putting the whole redux state on it...

update: - I added react-router-redux and I can only get it to update on a route change if I add the new 'router' to my mapped props.

I have a NavbarC component class with a render method like this:

render() {
  let { props } = this;

  return <header className="navbar">
    <nav>
      <h1><NavLink to="/" exact>Home</NavLink></h1>
      <NavLink to="/friends">Friends</NavLink>
    </nav>
    <div></div>
    <div className="center-flex-row">
      { props.busy ? <section className="nav-right"><p>working<span className="spacer"></span><span className="fa fa-spin fa-spinner"></span></p></section> :
        props.user ?
          <Logout onSignOutClick={props.onSignOutClick} user={props.user} /> :
          <Login onSignInClick={props.onSignInClick}/>
      }
    </div>
  </header>
}

And I use connect():

const mapStateToProps = (state) => {
  return { user: state.auth.user, busy: state.auth.busy
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onSignInClick: () => {
      dispatch(userLogin());
    },
    onSignOutClick: () => {
      dispatch(userLogout());
    }
  }
}

const Logout = ({ user, onSignOutClick }) => {
  return <section className="nav-right">
    <button className="btn" onClick={ onSignOutClick }>Sign Out</button>
  </section>
}

const Login = ({ onSignInClick }) => {
  return <section className="nav-right">
    <button className="btn" onClick={ onSignInClick }>Sign In</button>
  </section>
}

export const Navbar = connect(mapStateToProps, mapDispatchToProps)(NavbarC)
like image 743
Jason Goemaat Avatar asked Dec 07 '25 17:12

Jason Goemaat


2 Answers

I got it to work in three ways. I think connect is ignoring the props by default and replacing them, the example I based my code on didn't use 'ownProps'. So If I put the component in a route:

<Route path="/" component={Navbar}/>

And merge the properties in my mapStateToProps:

const mapStateToProps = (state, ownProps) => {
  console.log('mapping state:', state);
  console.log('  ownProps:', ownProps);
  return {
    user: state.main.auth.user,
    busy: state.main.auth.busy,
    ...ownProps
  }
}

That puts in the props from react-router (history, location, match) and causes the component to update because those values change when the route changes.

Another way is to bite the bullet and use react-router-redux, which puts a 'router' property on my state, which I then have to add to my mapStateToProps. Even though I don't care about the value, connect will detect that the props are different and re-render the component:

let store = createStore(
  combineReducers({
    main,
    router: routerReducer
  }),
  applyMiddleware(middleware),
}

// in Navbar.js
const mapStateToProps = (state, ownProps) => {
  return {
    user: state.main.auth.user,
    busy: state.main.auth.busy,
    router: state.router
  }
}

I can also specify pure=false in the options to connect() and that should re-render my component every time (at least it updates the right NavLink when I change routes for sure):

export const Navbar = connect(mapStateToProps, mapDispatchToProps, 
    undefined, { pure: false })(NavbarC)
like image 96
Jason Goemaat Avatar answered Dec 09 '25 20:12

Jason Goemaat


The best and easiest way to fix this issue is by doing

export default connect(mapStateToProps, mapDispatchToProps, undefined, { pure: false })(NavbarC)
like image 43
Morris S Avatar answered Dec 09 '25 21:12

Morris S



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!