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

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?

Related

there is a problem in using Middleware api call in react typescript component

this is a react-typescript project that uses middleware created with Axios to call Api anywhere in react component.
My App component is:
import React from "react";
import AllRiders from "./components/AllRiders";
function App() {
return (
<div className="App">
<AllRiders />
</div>
);
}
export default App;
This is my middleware structure
Constants file is :
const BASE_URL = "https://do-rider.cheetay.pk";
export const END_POINTS = {
ALL_RIDERS: `${BASE_URL}/alerts_rider?page=1` as string,
};
export const REQUEST_TYPE = {
GET: "GET" as string,
};
Types file is:
export const BASE_URL = "https://do-rider.cheetay.pk/alerts_rider?page=1";
export const config = {
headers: {
"Content-Type": "application/json",
Authorization: "token 6915953acf827475ce611bf14fd9820f51fbd454",
},
};
export type RidersData = {
id: number;
name: string;
mobile_number: string;
profile_image: null;
last_alert: LastAlert;
};
type LastAlert = {
id: number;
title: string;
is_seen: boolean;
description: string;
created_at: string;
updated_at: string;
rider: number;
};
Api middleware is following:
import axios from "axios";
interface Params {
method: string;
url: string;
data?: any;
}
export function apiCaller({ method, url, data }: Params) {
return axios({
method,
url,
data,
headers: {
Authorization: "token 6915953acf827475ce611bf14fd9820f51fbd454",
"Content-Type": "application/json",
},
})
.then((data) => data.data.results)
.catch((e) => console.log(e));
}
I am using this return axios apicaller through index file:
import { END_POINTS, REQUEST_TYPE } from "../../lib/constants";
import { RidersData } from "../../lib/types";
import { apiCaller } from "../apiCaller";
export function getAllRiders() {
apiCaller({
method: REQUEST_TYPE.GET,
url: END_POINTS.ALL_RIDERS,
});
}
And last of all I am using this index function in All Riders component:
import React, { useEffect, useState } from "react";
import axios from "axios";
import { RidersData, config, BASE_URL } from "../lib/types";
import { getAllRiders } from "../middleware/api";
const AllRiders = () => {
const [apidata, setData] = useState<Array<RidersData>> ([]);
const url = BASE_URL;
useEffect(() => {
const fetchData =(): any => {
try {
const data = getAllRiders();
const allRiders = data as <Array<RidersData>>;
setData(allRiders);
console.log(data, "========");
} catch (e) {
console.log(e);
}
};
fetchData();
}, []);
console.log(apidata, "apidata");
return (
<div>
<h1> All riders </h1>
<ul>
{apidata?.map((rider) => (
<li key={rider.id}>{rider.name}</li>
))}
</ul>
</div>
);
};
export default AllRiders;
And this is where error is occuring. the error is in useEffect and it says
Conversion of type 'void' to type '<Array>() => <RidersData>() => any' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.ts(2352)
Remove the extraneous tags (<>) in const allRiders = data as <Array<RidersData>>;
Should read
const allRiders = data as Array<RidersData>;
or simply
const allRiders = data as RidersData[];
Also, getAllRiders() returns a Promise. Either await it or use a .then(). So your useEffect() should look something like this:
useEffect(() => {
const fetchData = async () => {
try {
const data = await getAllRiders();
const allRiders = data as RidersData[];
setData(allRiders);
console.log(data, "========");
} catch (e) {
console.log(e);
}
};
fetchData();
}, []);
Return the apiCaller() request in your getAllRiders() function:
export function getAllRiders() {
return apiCaller({ // <--- added return
method: REQUEST_TYPE.GET,
url: END_POINTS.ALL_RIDERS,
});
}

Use effect not working in without refreshing the page

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

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;

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