Use effect not working in without refreshing the page - reactjs

I am making a app using ionic-react. Calling a api in useEffect but api is not getting call.
import classes from './index.module.scss';
import React, { useEffect, useState } from 'react';
import { IonContent, IonPage } from '#ionic/react';
import { LoggedInHeader, WalletCard } from '../../components';
import { Stack } from '#mui/material';
import { wallet } from '../../apis';
interface WalletProps { };
export const Wallet = (props: WalletProps) => {
const [walletHistory, setWalletHistory] = useState<any[]>([]);
useEffect(() => {
console.log("is this comingggggggggggggg")
let data = {
"user_id": localStorage.getItem("userid")
}
wallet(data)
.then((response)=> {
setWalletHistory(response.data.data)
})
.catch((error)=>{
console.error("Getting error at auth: ", error);
})
}, [])
return (
<IonPage>
<IonContent fullscreen>
<LoggedInHeader />
some content
</IonContent>
</IonPage>
)
}
If i add a dependency in useeffect then api is calling infinite time.
Wallet api calling file
instance.interceptors.request.use(function (config: AxiosRequestConfig) {
const token = localStorage.getItem('usertoken') || '';
if (token) {
const headers: AxiosRequestHeaders = {
Authorization: token
};
config.headers = headers;
}
return config;
});
export const wallet = (user_id:any) => instance({
method: 'GET',
url: `/customer/wallet_history`,
data: user_id,
responseType: 'json'
});
This is my api calling file and i am using axios instance

Related

ReactJS use a token stored in a function in a class that extends React.Component

I am using tokens around my ReactJS application. This is how I can get the value of the token in a page:
pages/Profile.js
import React from 'react';
import useToken from '../useToken';
export default function Profile() {
// Get token
const { token, setToken } = useToken();
const { userObject } = useToken();
return(
<div>
<p>
<b>Name:</b> {userObject?.name}<br />
<b>Email:</b> {userObject?.email}<br />
<b>Token:</b> {token}
</p>
</div>
);
}
Now I want to use the token inside a component. However the same appoch did not work, as it gives me an error "Unexpected token. A constructor, method, accessor, or property was expected.ts(1068)".
components/MyKnownDevices.js
import React from 'react';
import axios from 'axios';
import useToken from '../useToken';
export default class MyKnownDevices extends React.Component {
// Get token
const { token, setToken } = useToken(); // <---- THIS GIVES ERROR
const { userObject } = useToken(); // <---- THIS GIVES ERROR
// Respone handler
state = {
myKnownDevices: []
}
// Call API
componentDidMount() {
let config = {
headers: {
Accept: 'application/json',
'Access-Control-Allow-Origin': '*',
rejectUnauthorized: false,
}
}
let data = {
'HTTP_CONTENT_LANGUAGE': 'no',
rejectUnauthorized: false,
}
axios.get('https://127.0.0.1:5000/api/users/get_my_known_devices', data, config)
.then(res => {
const myKnownDevices = res.data;
this.setState({ myKnownDevices });
})
};
render() {
return (
<ul>
{
this.state.myKnownDevices
.map((device, index) => {
return (
<li key={index}>
<span>{device.known_device_updated_timestamp_saying}</span>
</li>
);
}
)
}
</ul>
)
};
};
useToken.js
import { useState, useEffect } from 'react';
import jwt_decode from "jwt-decode"
// const userObject = null;
export default function useToken() {
// Get token
const getToken = () => {
const userToken = localStorage.getItem('token');
return userToken
};
// Consts
const [token, setToken] = useState(getToken());
const [userObject, setUserObject] = useState(null);
// Effect
useEffect(() => {
if(token && token !== "undefined" && !userObject){
setUserObject(jwt_decode(token));
}
},[token]);
// Save token
const saveToken = userToken => {
if(userToken === null){
localStorage.removeItem('token');
setToken(null);
}
else{
localStorage.setItem('token', userToken.token);
setToken(userToken.token);
}
};
// Return value
return {
setToken: saveToken,
token,
userObject,
}
}
How can I get the value of the token inside my component MyKnownDevices.js?
This issue here is that useToken is a hook (https://reactjs.org/docs/hooks-intro.html) and hooks can only be used in functional components.
Given your code, I think the simplest way would be to rewrite your class component as a functional component, this should do the trick :
import React, {useEffect, useState} from "react";
import axios from "axios";
import useToken from "../useToken";
export default function MyKnownDevices() {
// Get token
const { token, setToken, userObject } = useToken();
const [myKnownDevices, setMyKnownDevices] = useState([]);
// Call API
// This is the same thing as your componentDitMount
useEffect(() => {
let config = {
headers: {
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
rejectUnauthorized: false,
},
};
let data = {
HTTP_CONTENT_LANGUAGE: "no",
rejectUnauthorized: false,
};
axios
.get(
"https://127.0.0.1:5000/api/users/get_my_known_devices",
data,
config
)
.then((res) => {
const myKnownDevices = res.data;
setMyKnownDevices(myKnownDevices);
});
}, []);
return (
<ul>
{myKnownDevices.map((device, index) => {
return (
<li key={index}>
<span>{device.known_device_updated_timestamp_saying}</span>
</li>
);
})}
</ul>
);
}
You must not use react hooks inside class components. You should rewrite your class component to functional

How to access useContext in Axios interceptor

I have created an Axios instance and a notificationContext to use in a React webapp.
I want to access the addNotification function of the notificationContext inside the request/response interceptor of the created Axios instance but since this is not a React component it's not possible. Is there a way to make and use this created Axios instance and interceptors as a React component?
NotificationContext.js
import React, { createContext, useState } from 'react';
const NotificationContext = createContext();
const NotificationProvider = ({ children }) => {
const [notifications, setNotifications] = useState([]);
const addNotification = (type, title, description) => {
const notification = {
id: Date.now(),
type,
title,
description,
};
setNotifications([notification, ...notifications]);
};
const removeNotification = (id) => {
setNotifications(notifications.filter((notification) => notification.id !== id));
};
return <NotificationContext.Provider value={{ notifications, addNotification, removeNotification }}>{children}</NotificationContext.Provider>;
};
export { NotificationContext, NotificationProvider };
App.js
The NotificationProvider is wrapped around the NotificationList component
const App = () => (
<BrowserRouter>
<AuthProvider>
<NotificationProvider>
<NotificationList />
<Router />
</NotificationProvider>
</AuthProvider>
</BrowserRouter>
);
export default App;
apiClient.js
import axios from 'axios';
// import { useContext } from 'react';
// import { NotificationContext } from '../context/NotificationContext';
const apiClient = axios.create({
baseURL: process.env.REACT_APP_API,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
withCredentials: true,
timeout: 10000,
});
apiClient.interceptors.request.use(
(config) => {
return config;
},
(error) => {
return Promise.reject(error);
// How to access AddNotification here
},
);
apiClient.interceptors.response.use(
(response) => {
return Promise.resolve(response);
},
(error) => {
if (!error.response) {
// network error
// console.log('Network error');
// How to access AddNotification here
} else {
const response = error.response.data;
// How to access AddNotification here
}
return Promise.reject(error);
},
);
export default apiClient;
You can export the axios instance
create a functional component
access the context
init interceptor in useMemo
Example (just for an idea):
function Interceptor({children}) {
const {addNotification} = useContext(NotificationContext)
useMemo(() => {
apiClient.interceptors.response.use(
(response) => {
return Promise.resolve(response);
},
(error) => {
if (!error.response) {
addNotification()
} else {
const response = error.response.data;
addNotification()
}
return Promise.reject(error);
},
);
}, [addNotification])
return <>{children}</>
}
and in App.js
const App = () => (
<BrowserRouter>
<AuthProvider>
<NotificationProvider>
<Interceptor> // here
<NotificationList />
<Router />
<Interceptor />
</NotificationProvider>
</AuthProvider>
</BrowserRouter>);
export default App;

Next.js: How to create get request using React Query

I want to integrate to React query for fetching the data from server.
So far I've been fetching the rest api via Axios.
I have created a custom hook for fetching and want to transform and implement with react query.
While trying to implement the same logic I encountered an error trying to destructure the fetched data const { data } = useApiRequest(headersUrl):
error - TypeError: (0 , _hooks_useApiRequest__WEBPACK_IMPORTED_MODULE_1__.UseApiRequest) is not a function
Here is the old logic for fetching
import * as React from "react";
import { useState, useEffect } from "react";
import axios from "axios";
import { HeaderToken } from "../services/api";
export const useApiRequest = (url: any) => {
const [data, setData] = useState<[] | any>([]);
useEffect(() => {
const fetchData = () => {
axios
.get(url, {
headers: {
Authorization: `Basic ${HeaderToken}`,
},
})
.then((response) => {
setData(response.data);
})
.catch((error) => console.error(error));
};
fetchData();
}, [url]);
return { data };
};
And here is how I'm trying to convert it:
import { HeaderToken } from "../services/api";
import { useQuery } from "react-query";
export const useApiRequest = (url: any) => {
const { isLoading, data } = useQuery("bc", async () => {
const response = await fetch(url, {
method: "get",
headers: {
Authorization: `Basic ${HeaderToken}`,
"Content-Type": "application/json",
},
});
if (!response.ok) throw new Error(response.statusText);
return await response.json();
});
return { data };
};
I can't see the problem, actually, I tried the same code you shared with a local API I have and it's working
The Hook
import { useQuery } from 'react-query'
export const clientAPI = (url) => {
const { isLoading, data } = useQuery("bc", async () => {
const response = await fetch(url, {
method: "get"
});
if (!response.ok) throw new Error(response.statusText);
return await response.json();
});
return { data };
};
React Component
import * as React from "react";
import { clientAPI } from "../hooks/clientAPI";
export default function Home() {
const { data } = clientAPI('http://localhost:5000/')
return (
<div>
{JSON.stringify(data)}
</div>
)
}
_app.js
import { QueryClient, QueryClientProvider, useQuery } from 'react-query'
const queryClient = new QueryClient()
function MyApp({ Component, pageProps }) {
return (<QueryClientProvider client={queryClient}>
<Component {...pageProps} />
</QueryClientProvider>)
}
export default MyApp
I'm using next#11.1.2, react-query#3.28.0
what are the versions you are using?

React Custom Hooks Circular Dependency

I have two custom hooks i.e useFetch and useAuth. useAuth has all API calls methods (e.g logIn, logOut, register, getProfile etc) and they use useFetch hook method for doing API calls. useFetch also uses these methods for example logOut method when API return 401, setToken etc. So, they both need to share common methods. But that results into circular dependency and call size stack exceeded error. How to manage this
UseFetch.js
import React, { useState, useContext } from "react";
import { AuthContext } from "../context/authContext";
import { baseURL } from "../utils/constants";
import { useAuth } from "./useAuth";
const RCTNetworking = require("react-native/Libraries/Network/RCTNetworking");
export const useFetch = () => {
const {token, setAuthToken, isLoading, setIsLoading, logIn, logOut} = useAuth();
const fetchAPI = (method, url, body, isPublic, noBaseURL) => {
setIsLoading(true);
const options = {
method: method
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
},
};
return fetch(url, options, isRetrying).then(() => {
......
})
......
};
return { fetchAPI };
};
UseAuth.js
import React, { useContext, useEffect } from "react";
import { AuthContext } from "../context/authContext";
import { useFetch } from "./useFetch";
export const useAuth = () => {
const {
removeAuthToken,
removeUser,
setUser,
...others
} = useContext(AuthContext);
const { fetchAPI } = useFetch();
const register = (body) => {
return fetchAPI("POST", "/customers/register", body, true);
};
const logIn = (body) => {
return fetchAPI("POST", "/customers/login", body, true);
};
const logOut = () => {
return (
fetchAPI("POST", "/customers/logout")
.catch((err) => console.log("err", err.message))
.finally(() => {
removeAuthToken();
removeUser();
})
);
......
};
return {
...others,
register,
logIn,
logOut,
};
};

How to fetch the data from using axios header?

I'm trying to fetch the json data using axios. Could you please tell me what am i doing wrong here
I have tried doing it using hooks as well but to no avail. i have put it below the class based component please have a look at it. Could you please tell me what am i doing wrong here
API : https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=API_KEY
API_ KEY : 3055f8f90fa44bbe8bda05385a20690a
import React, { Component } from "react";
import axios from "axios";
import Post from "../../Component/Post/Post";
export default class Home extends Component {
state = {
posts: [],
};
componentDidMount() {
axios
.get(
"https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=API_KEY",
{
headers: {
" API_KEY ": "3055f8f90fa44bbe8bda05385a20690a",
},
}
)
.then((response) => {
console.log(response.data);
this.setState({ posts: response.data });
})
.catch((err) => {
console.log("API call error:", err.message);
});
}
render() {
const posts = this.state.posts.map((post) => {
return <Post key={post.id} />;
});
return <div>{posts}</div>;
}
}
import React, { useState, useEffect } from "react";
import Post from "../../Components/Post/Post";
import axios from "axios";
const HomePage = () => {
const [posts, setPosts] = useState("");
let config = { Authorization: "3055f8f90fa44bbe8bda05385a20690a" }; //3055f8f90fa44bbe8bda05385a20690a
const url =
"https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=API_KEY";
useEffect(() => {
AllPosts();
}, []);
const AllPosts = () => {
axios
.get(`${url}`, { headers: config })
.then((response) => {
const allPosts = response.data;
setPosts(allPosts);
})
.catch((error) => console.error(`Error: ${error}`));
};
return (
<div>
<Post className="Posts" posts={posts} />
</div>
);
};
export default HomePage;
Replace your previous codes with this:
let config = {'Authorization': 'MY-API-KEY'};//3055f8f90fa44bbe8bda05385a20690a
axios.get('https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=API_KEY', {headers: config})
Also, refer to this question to get a deep understanding of the problem:
Setting authorization header in axios

Resources