Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why React-router v4 <Link/> does not work (Changes url but not rendering content)?

I have server side React/Redux/Express app. React-router v4 provides solution for a server app with Switch and I need to use something to change location from my NavBar component

App

import React, { Component } from 'react'

import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'

import { Switch, Route, Redirect, Link} from 'react-router-dom'
import FirstPage from './FirstPage'
import Test from './Test'
import LoginPage from './login/LoginPage'
import NoMatch from '../components/NoMatch'
import NavBar from '../components/NavBar'

import * as loginActions from '../actions/login'

import 'bootstrap/dist/css/bootstrap.css';

class App extends Component {

  render(){
    return (
      <div>
            <NavBar/>

            <h1>EffortTracker v3.0.1</h1>

        <Switch >
            <Route exact path="/" render={loginRedirect(<FirstPage/>)}/>
              <Route path="/first" render={loginRedirect(<FirstPage/>)}/>
              <Route path="/second" render={loginRedirect(<Test/>)}/> />
              <Route path="/login" render={()=><LoginPage {...this.props.login}/>} />
              <Route component={NoMatch}/>
        </Switch>

          <Link to={'/first'}>First</Link>
      </div>
    )
  }
}

const loginRedirect=(component) => {
    if(!isLoggedIn()) return ()=> <Redirect to='login'/>

    return ()=> component
}

const isLoggedIn= ()=>{
    let token = localStorage.getItem('token')

if (token !== null)return false
    else return true

}

const mapStateToProps = state => ({
    login: state.login,
    error: state.error,
    isLoading: state.isLoading,
})

const mapDispatchToProps = dispatch => ({
    loginActions: bindActionCreators(loginActions, dispatch)
})

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(App)

Need to change from NavBar

import React from 'react'
import { Link, NavLink } from 'react-router-dom'

import classnames from 'classnames'

const NavBar =()=> {
    return (
        <nav className={classnames("navbar", "navbar-inverse bg-inverse")}>
            <form className="form-inline">
                <Link to={'/'}>
                    <button className={classnames("btn", "btn-sm", "align-middle", "btn-outline-secondary")}
                            type="button">
                        Smaller button
                    </button>
                </Link>

                <NavLink to='/login'>
                    Login
                </NavLink>
            </form>

        </nav>
    )
  }

export default NavBar

If I navigate it manually from browser url its work just fine but if I click a Link or NavLink url is updated but not the App Switch. Also I have an issue when loginRedirect to /login it does not appear and need to refresh page (possible that this two is related ). How to fix this?

like image 891
victor zadorozhnyy Avatar asked Oct 17 '22 09:10

victor zadorozhnyy


1 Answers

I think the problem here is with redux .. because it blocks rerendering the components as long as the props didn't change,

This is because connect() implements shouldComponentUpdate by default, assuming that your component will produce the same results given the same props and state.

The best solution to this is to make sure that your components are pure and pass any external state to them via props. This will ensure that your views do not re-render unless they actually need to re-render and will greatly speed up your application.

If that’s not practical for whatever reason (for example, if you’re using a library that depends heavily on React context), you may pass the pure: false option to connect():

function mapStateToProps(state) {
  return { todos: state.todos }
}

export default connect(mapStateToProps, null, null, {
  pure: false
})(TodoApp)

here are links for more explanation:

react-redux troubleshooting section

react-router DOCS

like image 109
Eslam Yahya Avatar answered Oct 27 '22 10:10

Eslam Yahya