Ganda Rain Panjaitan
Ganda Rain Panjaitan

Reputation: 959

How to call useNavigation inside axios file

I try to implement axios interceptor, for my request. So when the error response is forbidden (401), I want to clear token and navigate to login screen. But when I want to call useNavigation from react navigation v5 inside my axios file, it always shows error like this.

React Hook "useNavigation" is called in function "refreshAccessToken" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter.

This is my axios file code,

import axios from 'axios'
import AsyncStorage from '@react-native-community/async-storage'
import {useNavigation} from '@react-navigation/native'
import {generateRandomString, getDeviceInfo} from '../helper/helper'

const base = axios.create({
  baseURL: '------',
  timeout: 500000,
  headers: {
    'Content-Type': 'application/json'
  }
})

async function refreshAccessToken() {
  const navigation = useNavigation()
  try {
    const refreshToken = await AsyncStorage.getItem('refreshToken')
    const response = await base.get('------', {
      refreshToken
    })
    await AsyncStorage.setItem('accessToken', response.data.accessToken)
    console.log('Response from refresh access token ', response)
    return Promise.resolve(response.data)
  } catch (error) {
    console.log('Error from refresh access token', error.response)
    if (error.response.data.errors.flag === 'INVALID_REFRESH_TOKEN') {
      await AsyncStorage.removeItem('refreshToken')
      await AsyncStorage.removeItem('accessToken')
    }
    return Promise.reject(error)
  }
}

base.interceptors.request.use(
  async function (config) {
    const accessToken = await AsyncStorage.getItem('accessToken')
    config.headers.authorization = accessToken
    const deviceInfo = await getDeviceInfo()
    const latitude = await AsyncStorage.getItem('latitude')
    const longitude = await AsyncStorage.getItem('longitude')
    config.headers['accept-language'] = 'id-ID'
    config.headers['version'] = '1.0.0'
    config.headers['date'] = new Date().toUTCString()
    config.headers['x-coordinate'] = `${latitude};${longitude}`
    config.headers['x-trace-id'] = generateRandomString()
    config.headers['x-device'] = `${deviceInfo.deviceType}/${deviceInfo.deviceName}/${deviceInfo.deviceVersion}/${deviceInfo.deviceUid}`
    return config
  },
  function (error) {
    return Promise.reject(error)
  }
)

base.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config
    if (error.response.status === 403 && !originalRequest._retry) {
      originalRequest._retry = true
      const accessToken = await refreshAccessToken()

      originalRequest.headers.Authorization = accessToken
      return axios(originalRequest)
    }
    return Promise.reject(error)
  }
)

export default base

Upvotes: 1

Views: 1410

Answers (1)

emeraldsanto
emeraldsanto

Reputation: 4741

You can't, hooks are only meant to be called inside components. There is a guide on how to navigate without the navigation prop you could use for this situation though.

You could also send an event (via a custom event emitter) and set up a listener anywhere else in your app where the navigation prop is available.

Upvotes: 0

Related Questions