1

How can I conditionally redirect to a page if the axios api is empty or a state is empty initially. In the following code I'm updating the state using axios and the user information is available in the state but the code keeps on calling to the http://userapi.com/login in loop. What I'm trying to achieve is, if the userinfo state is empty initially then redirect to the login page and authenticate.

class MyComponent extends React.Component {
  constructor() {
    super()
    this.state = {
      userinfo:{}
    }
  }
  
  componentDidMount(){
    axios.get('http://userapi.com/user')
    .then(res => {
        const userinfo = res.data;
        this.setState({ userinfo });
    })
    .catch(err => {
        console.log("Fetch error", err)
    })
    if (Object.keys(this.state.userinfo).length === 0) {
        window.location = 'http://userapi.com/login';
    }
  }
  render() {
    return (
      <React.Fragment>
        <Header>Welcome</Header>
      </React.Fragment>
    )
  }
}

I'm able to redirect fine but issue is with continuous loop. Even though the user information is storing the redirection is called (happens in loop)

Lalas M
  • 789
  • 4
  • 16
  • 1
    wrap your component in withRouter Hoc then use props.history.push("/yourroute") – Sujit.Warrier Sep 25 '20 at 02:15
  • if you are using react -router – Sujit.Warrier Sep 25 '20 at 02:16
  • 1
    I'm able to redirect fine but issue is with continuous loop. Even though the user information is storing the redirection is called (happens in loop) – Lalas M Sep 25 '20 at 02:19
  • As @Sujit.Warrier said, use the `push` method, as `window.location = ...` will do a hard navigation, reloading your app and causing everything to re-render. In addition, this check is probably better put somewhere higher up your component tree. Closer to the root App component. It doesn't make sense for the `Header` component to check if they're logged in or not. Should probably even be done *above* all the router stuff – Jayce444 Sep 25 '20 at 02:21
  • This will also mean that it will be in a place that doesn't get re-rendered when you navigate between pages, which should fix the issue – Jayce444 Sep 25 '20 at 02:22
  • Does this answer your question? [How to implement authenticated routes in React Router 4?](https://stackoverflow.com/questions/43164554/how-to-implement-authenticated-routes-in-react-router-4) – Emile Bergeron Sep 25 '20 at 04:02

4 Answers4

2

Axios returns Promise so the code with if condition below executes before the function that updates the state in then block. So if you need to check the updated state value after the request is successful, put your conditional inside then block.

componentDidMount() {
    axios
      .get('http://userapi.com/user')
      .then((res) => {
        const userinfo = res.data;
        this.setState({ userinfo }, () => {
          if (Object.keys(this.state.userinfo).length === 0) {
            window.location = 'http://userapi.com/login';
          }
        });
      })
      .catch((err) => {
        console.log('Fetch error', err);
      });
  }
anonymous
  • 2,008
  • 3
  • 9
  • 19
2

You can try the following approach:

class HeaderComponent extends React.Component {
  constructor() {
    super()
    this.state = {
      userinfo:{}
    }
  }
  
  componentDidMount(){
    axios.get('http://userapi.com/user')
    .then(res => {
        const userinfo = res.data;
        this.setState({ userinfo });
    })
    .catch(err => {
        console.log("Fetch error", err)
    })
  }
  componentDidUpdate(prevProps, { userinfo }) {
    if (userinfo !== this.state.userinfo
        && Object.keys(this.state.userinfo.w3idUser || {}).length === 0) {
        window.location = 'http://userapi.com/login';
    }
  }
  render() {
    return (
      <React.Fragment>
        <Header>Welcome</Header>
      </React.Fragment>
    )
  }
}

The problem was that this.state.w3idUser never exists since you're mapping the response into userInfo state.

Heri Hehe Setiawan
  • 1,362
  • 1
  • 10
  • 14
0

i guess the issue is componentDidMount, you are redirecting before axios finish it's get request, refactor your code like below, you can show the sort of spinner until axios return value:

componentDidMount(){
axios.get('http://userapi.com/user')
.then(res => {
    const userinfo = res.data;
    this.setState({ userinfo });
   if (Object.keys(this.state.w3idUser).length === 0) {
    window.location = 'http://userapi.com/login';
}
})
.catch(err => {
    console.log("Fetch error", err)
})

}

it depends on the router you're using but if you want the javascript way check the code below:

// Simulate a mouse click:
window.location.href = "http://www.w3schools.com";

// Simulate an HTTP redirect:
window.location.replace("http://www.w3schools.com");
Besufkad Menji
  • 959
  • 3
  • 9
0

Here when you are getting response...

.then(res => {
        const userinfo = res.data;
        this.setState({ userinfo });
    })

Check the res.data for user info. If you did receive a user then you can setState, if no user redirect to login page.

As far as redirecting look into react-router or react-router-dom

I wouldn't use pure javascript for redirecting/navigating in a React App.

Jason
  • 289
  • 8
  • Hi Jason i know the pure javascript is unconventional but here i need to use this and later i may change it – Lalas M Sep 25 '20 at 02:23
  • Ok. Well however you would like to redirect, do so in the _then_ statement after checking API response. – Jason Sep 25 '20 at 02:31