React Router: state variable updated with setState not being passed down to Route correctly

react-router location state
react router-dom
react router history
withrouter react router-dom
react redirect
react router link state
react router params
react-router basename

So, I have the following problem: I want to allow users to set the language of my portfolio. To do so, I provide them with two links in the initial <Language /> component, which set the state of <App /> and then lead the user to the home screen - <Home />. The problem is, the updated this.state.language is not passed down to <Home />; instead, the initial value it had is passed down.

My code:

// <App /> component

class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            language: "none"
        }
    }

    changeLanguage = event => {
        event.preventDefault()
        this.setState({ language: event.target.id }, () => {
            window.location.href = "/home"
        })
    }

    render() {
        return (
            <BrowserRouter>
                <div id="app">
                    <Route
                        exact
                        path="/"
                        render={() => (
                            <Language changeLanguage={this.changeLanguage} />
                        )}
                    />
                    <Route
                        path="/home"
                        component={() => {
                            return <Home language={this.state.language} />
                        }}
                    />
                    <Route
                        path="/about"
                        render={() => {
                            return <About language={this.state.language} />
                        }}
                    />
                    <Route
                        path="/projects"
                        render={() => {
                            return <Projects language={this.state.language} />
                        }}
                    />
                    <Route
                        path="/contact"
                        render={() => {
                            return <Contact language={this.state.language} />
                        }}
                    />
                </div>
            </BrowserRouter>
        )
    }
}

// <Language /> component

const Language = props => {
    return (
        <div id="language">
            <h1>Choose your language.</h1>
            <div className="lang-options">
                <a
                    href="/home"
                    className="lang-link"
                    id="pt_BR"
                    onClick={props.changeLanguage}
                    title="Português Brasileiro"
                >
                    <img
                        src="https://s3-sa-east-1.amazonaws.com/myhostedfiles.raulf/Images/svg-icons/brazil-flag.svg"
                        alt="A bandeira brasileira. Clique para ter acesso ao site em português."
                    />
                </a>
                <a
                    href="/home"
                    className="lang-link"
                    id="en_US"
                    onClick={props.changeLanguage}
                    title="American English"
                >
                    <img
                        src="https://s3-sa-east-1.amazonaws.com/myhostedfiles.raulf/Images/svg-icons/usa-flag.svg"
                        alt="The american flag. Click to access the site in english."
                    />
                </a>
            </div>
            <h1>Escolha seu idioma.</h1>
        </div>
    )
}

// <Home /> component

const Home = (props) => {
    console.log(props.language)
    return (
        <div id="home">
            <div className="bg-filter" />
            <Navbar />
            <TypedIntro />
            <LinkBox />
        </div>
    )
}

When the <Home /> component is loaded, console.log(props.language) logs none to the console, which is the initial value this.state.language is set to. Can anybody explain to me why won't it update, and how to fix it?

Setting window.location.href is going to refresh the page. That will lose all your state. Change your <a> tags to use the react-router <Link to="/home"> tag instead.

Here's a CodeSandbox to help illustrate what is going on:

An alternative to handle state in React: the URL !, React + React-Router + URL + state management = <3. have no impact on what you'll see on the first loading of the app. Ideally, rather than a string , it would be more convenient to manipulate a JS object properly formatted. So if the query value in our input is javascript , we'll have to update our URL  React Router: state variable updated with setState not being passed down to Route correctly Vis Team January 21, 2019 So, I have the following problem:I want to allow users to set the language of my portfolio.

Have you tried exploring this as a solution? You would have a file where you define your keys to each language and pass around an i18n object to access each key. This is an anti-pattern as you are trying to mutate state with multiple components.

Passing State to Components Rendered by React Router (and Other , If you want details on that, please feel free to read on :) But in React, passing state (or helper methods) is where all the power comes from The Route path in that code is using the render method to pass an inline function In the above, the component "NoMatch" is not given a route, so all routes which  To me, the ID should not be modified, so we don't have to put it in the state. Is there any particular reason why you don't pass a function as the first argument of this? this.setState({status: !this.state.status}, this.updateLibraryCount); Thanks again! See you :)

You were having issues because you were using windows.location.href it will refresh the app. And after that you will get a new instance of the app and you will lose the state of the app. And it was the reason you were getting initial state in console.

Change windows.location.href to this.props.history.push() but to do so you need to wrap App component with withRouter HOC from 'react-router-dom'. I have changed your code in some places check that out. And try to use Link tag instead of a tag.

import { BrowserRouter , Route,  withRouter} from "react-router-dom";
.....

class App extends React.Component {
  constructor(props) {
      super(props)
      this.state = {
          language: "none"
      }
  }

  changeLanguage = event => {
      event.preventDefault()
      // react-router passes "history" as props
      this.setState({ language: event.target.id }, () => this.props.history.push('/home'))
  }

  render() {
      return (

          <div id="app">
            <Route
              exact
              path="/"
              render={() => (
                  <Language changeLanguage={this.changeLanguage} />
              )}
            />
            <Route
              path="/home"
              component={() => {
                  return <Home language={this.state.language} />
              }}
            />            
           </div>
      )
  }
}

// wrapping App component with "withRouter" HOC
const RouterApp = withRouter(App)

// <NewApp /> Component
// you need to do this because component wrapped inside
// "withRouter" HOC must be inside "Router" component
const NewApp = () => {
 return <BrowserRouter>
        <RouterApp />
  </BrowserRouter>
}

// <Language/> Component
const Language = props => {
  return (
      <div id="language">
          <h1>Choose your language.</h1>
          <div className="lang-options">
              <p
                  className="lang-link"
                  id="pt_BR"
                  onClick={props.changeLanguage}
                  title="Português Brasileiro"
              >
                  Português
              </p>
              <p
                  className="lang-link"
                  id="en_US"
                  onClick={props.changeLanguage}
                  title="American English"
              >
                  American
              </p>
          </div>
          <h1>Escolha seu idioma.</h1>
      </div>
  )
}   

// <Home Component/>
const Home = (props) => {
  console.log(props.language)
  return (
      <div id="home">
          Home Component
          <p>Language: {props.language}</p>
      </div>
  )
}

// render NewApp component
ReactDOM.render(<NewApp />, document.getElementById('root'));

How To Pass Multiple Route Parameters in a React URL Path, I wanted to pass more than one route parameter in a React URL route This will not be an in-depth explanation of that, but it is the router I'm This is a dynamic route with placeholders for `:id` that will be updated on-the-fly based on From there it can be set to local component state, used to fetch data,  State Updates May Be Asynchronous . React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state. For example, this code may fail to update the counter:

You should use <Link to='/home'> instead of window.location.href = "/home".

This will reload the page and reload the component. Also it disables react's capability as a SPA.

Conquer navigation state with React-router and Redux, If not, you may want to check out my article on Understanding Redux Notice how the app stays on a current route, but when the button is clicked it The emojiLand higher order component does this by passing the appState other route components, we can successfully redirect through all the routes! React Props vs. State. Passing only props from component to component doesn't make the component interactive, because nothing is there to change the props. Props are read-only. That's the time when React State comes into play which can be changed. The state is co-located to a React component.

ReactTraining/react-router, @joewood Passing state down from parent to child components The actual anti​-pattern is passing props through route boundaries – in setState({flashes: _.​without(this.state.flashes, flash)}); }, render: We want to keep the issue tracker and updates on issues to only Please correct me if I am wrong. Mapstatetoprops not called when state changes. MapStateToProps not being called even after changing STATE in , Do you want to request a feature or report a bug? I am retrieving data from Salesforce using JS remote Actions and populating data in React JS. mapStateToProps will not be called when USER_SIGNUP_SUCCESS or USER_SIGNUP_FAIL is dispatched since you aren't changing the state in those cases.

How to Pass, Access & Update Parent State from Child Components , In this tutorial, you'll learn to access and update the state of a parent from a PHP API backend and stored in a state variable named contacts . This is the example ContactForm child component: and use the React setState() method to update the component state with What's new with React Router 6? Even though UI elements get updated with the XHR response, the new store props are not being passed down to the external component. In order for that to happen I needed to use this.forceUpdate() which then passed the new store props to the external component to render the data and display on the local component.

Route Params ― Scotch.io, Route parameters are parts of the URL that will change based on the object we want to With react-router-dom , we designate a dynamic portion of the URL to be We will see in a little bit that we will have access to this variable in our route. being passed into our route and use it to query the correct user from the API. Because state updates are actually requests, it is not correct to expect the new values to be present in this.state immediately after a call to setState. This example is not meant to imply that state values update immediately – assume that the "after" version of state is being shown after the state update has propagated completely and

Comments
  • I was using window.location.href to try and prevent the browser from redirecting before setting the state, but it wasn't working anyway. Your solution worked perfectly! Thanks a lot!
  • I was using window.location.href to try and prevent the browser from redirecting before setting the state, but it wasn't working. My problem has been solved by using <Link /> components instead of <a> tags. Thanks anyway!