what is the equivalent of this.props.history.push('/some_route') of react class components in hooks?

Viewed 6988

I am trying to accomplish this

import {isAuthorized} from '../somewhere'
async componentDidMount() {
   const authorized = await isAuthorized()
   if(!authorized){
   this.props.history.push('/login')
  }
}

in react hooks, how can I achive this exact functionality, thanks

5 Answers

You can use useHistory hook to get access to the history instance and call history.push to inside a useEffect to navigate to the desired route.

import {isAuthorized} from '../somewhere';
import { useHistory } from "react-router-dom";

function SomeComponent(props) {
  const history = useHistory()

  useEffect(() => {
    const navigate = async () => {
       const authorized = await isAuthorized();

       if(!authorized){
          history.push('/login')
       }
    }

    // call the async function 
    navigate()

  }, [])
}

Keep in mind React doesn't allow the callback for useEffect to be an async function because of possible race conditions. So you have to define a new async function inside the useEffect hook and invoke it.

You will need to use useEffect hook:

useEffect(async () => {
  const authorized = await isAuthorized()
   if(!authorized){
   props.history.push('/login') // note: not this.props but simply props
  }
},[]) // empty array to call effect in mounted period.

But react doesn't allow to perform async action directly in useEffect hook. You could wrap an async function inside that:

useEffect(() => {
  (async () => {
   //...
  })()
},[])

For further detail, you may take a look into my another post.

useEffect(() => {
const apiCall = async () => {
  const authorized = await isAuthorized()
   if(!authorized){
   props.history.push('/login');
  }
}

apiCall()
},[]) 

You need to wrap your await in an async function and call that async function apiCall in the body of the useEffect function.

I think in this case you could use useHistory hook which is used like this:

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

export default props => {
    const history = useHistory()

    React.useEffect(() => {
        const isLogged = async () => {
            const authorized = await isAuthorized()
            return authorized
        }
        const authorized = isLogged()
        if(!authorized)
            history.replace('/login') // to replace the route , in order to push : history.push('/login')
    },[])
}

EDIT:

Yes, it cannot be made async, I changed the answer. Sorry.

There is one more alternative which comes from redux-react-hooks library's useDispatch() hook. It generally is used to call the store actions which in turn call's the store reducer but you can also pass push method defined in react-router-redux for passing in your routes/pathname data.

import {isAuthorized} from '../somewhere';
import {useDispatch} from "redux-react-hook";
import {push} from "react-router-redux";
async componentDidMount() {
   const authorized = await isAuthorized();
   const dispatch = useDispatch();
   if(!authorized){
      dispatch(push('/login'));
  }
}
Related