React app keeps sending multiple request on its own - reactjs

I'm new to react and I'm trying to build a Weather App for my project. It keeps sending the request to the API I'm using which is OpenWeatherMap API.
I'm using Axios to send the request.
Here's what my code looks like:
import React, {useEffect, useState} from 'react';
import axios from 'axios';
const App = () => {
const [ data, setData ] = useState(null);
const APIKEY = <APIKEY>;
useEffect(()=>{
window.navigator.geolocation.getCurrentPosition(
async position=>{
await axios.get(`https://api.openweathermap.org/data/2.5/onecall?lat=${position.coords.latitude}&lon=${position.coords.longitude}&appid=${APIKEY}`)
.then(response=>{
setData(response.data);
}).catch(error=>{
console.log(error);
})
}
)
}, []);
console.log(data);
return<div>hello</div>
}
export default App;
I tried using class components it doesn't work either way.

Related

Is it anti-pattern to handle getServerSideProps api requests with redux-thunk then access it's data in page with useSelector?

In next.js We can request to api in getServerSideProps and pass data to page through props like this :
method 1: (next default approach)
const Page: NextPage = ({page}) => {
return <div>{JSON.stringify(data)}</div>;
};
// This gets called on every request
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch(`https://.../data`)
const data = await res.json()
// Pass data to the page via props
return { props: { data } }
}
export default Page
I work in large scale project So I want to manage all server and client request only using thunk and then store it to redux and use in page like this:
method 2: (with next-redux-wrapper)
import React from 'react';
import {NextPage} from 'next';
import {useSelector} from 'react-redux';
import {wrapper, State, fetchData } from '../store';
const Page: NextPage = () => {
const {data} = useSelector(state => state);
return <div>{JSON.stringify(data)}</div>;
};
export const getServerSideProps = wrapper.getServerSideProps(store => ({req, res, ...etc}) => {
store.dispatch(fetchData());
});
export default Page;
I want to know which is better approach ?
Is it anti-pattern to use second approach to store all pre-rendered data and client side state of app in redux?

Use react hook inside a axios config file

i have a axios config file, and i call react hook {Auth Context} in that file with the purpose to fetch the token in react context api. but i got an error like this "React Hook 'useAuth' cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function"
AuthContext.js
import React, { useContext, createContext, useState } from "react";
const AuthContext = createContext();
export function useAuth() {
return useContext(AuthContext);
}
export function AuthProvider({ children }) {
const [currentToken, setCurrentToken] = useState("");
const [isAuth, setIsAuth] = useState(false);
function login(token) {
setCurrentToken(token);
setIsAuth(true);
}
const value = {
login,
currentToken,
isAuth,
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
and my axios config file something like this
AxiosConfig.js
import axios from "axios";
import { useAuth } from "./AuthContext";
const { currentToken } = useAuth(); //my Reeact Context
export default axios.create({
baseURL: "http://127.0.0.1:8000",
headers: {
"Content-type": "application/json",
Authorization: `Bearer ${currentToken}`,
},
});
what is the best way to achieve that goal ?
Thank you in advance
you can create an api and set the token when it's needed, since your api is the same throughout the code, this will work.
const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_END_POINT,
});
export const setApiToken = (token: string) => {
api.defaults.headers.common["Authorization"] = `bearer ${token}`;
};
As several users have pointed out you cannot use a hook outside the React component. I have very similar set up in my project and store my API key in the local storage, this also adds a benefit of persisting API key.
// src/api/index.js
import axios from "axios";
import { API_URL, LOCALSTORAGE_API_KEY } from "../utils/constants";
export const signedRequest = () => {
const apiKey = localStorage.getItem(LOCALSTORAGE_API_KEY);
return axios.create({
baseURL: API_URL,
headers: apiKey ? { "Authorization": `Bearer: ${apiKey}` } : {},
});
};
export const unsignedRequest = () => {
const request = getSignedRequest();
request.defaults.headers = {};
return request;
};
Usage:
signedRequest().get<AdminDashboard.UsersResponse>("/dashboard");
And if you need to perform a request w/o Authorization you can do it:
unsignedRequest().get<AdminDashboard.UsersResponse>("/public");
Hooks were not meant to be used outside of a component, and useContext and useAuth(which uses useContext) is a hook. Here's a quote from freecodecamp:
You can not use hooks outside a component function, it is simply how they work. But, you can make a composition of hooks. React relies on an amount and order of how hooks appear in the component function. So don't even think of wrapping those calls with conditional logic of some sort.
As you read above, you are not supposed to do this in react applications.

Duplicate axios calls in react

I am working on a create-react-app generated app and I have an API call to a local JSON file.
Somehow this code generates 8 API calls in a roll.
import '#css/request.scoped.css';
import { useState } from 'react';
import { getAllData } from '#api/api';
function Request() {
let [user, setUser] = useState('');
function changeUser(data) {
setUser(data);
}
getAllData().then((reply) => {
changeUser(reply.data[0].item_name);
});
return <>{user}</>;
}
export default Request;
and here is my Axios instance
import axios from "axios";
const request = axios.create({
baseURL:'./example.json',
timeout: 20000,
});
export const getAllData = () => {
return request({
method: 'get',
url: '',
});
};
Can someone tell me why this happens?
I suspect the most likely cause is that the component is being re-rendered, and currently the logic is to make the API call on every render.
You can set the logic to occur only on the first render of the component with useEffect:
import { useState, useEffect } from 'react';
// then...
useEffect(() => {
getAllData().then((reply) => {
changeUser(reply.data[0].item_name);
});
}, []);
The empty dependency array passed to useEffect means it would open happen once when the component is first loaded, not on subsequent renders. Any dependency you add to that array would cause the operation to be invoked again any time that dependency changes between renders.

How to use axios to make requests in react

I started learning React about 3 or 4 months ago. Initially went through Codecademy's course, and have since polished up a lot with other courses and tutorials, the main of which used Axios for get requests without really explaining Axios. I decided to go back to the "Ravenous" yelp clone project at Codecademy, the instructions of which are for class components, and thought it would be a nice challenge to complete that same project but with functional components. Everything was perfect until it was time to wire up the Yelp api, and given my lack of knowledge with axios and requests in general, I can't pinpoint what I'm doing wrong. I'm almost certain that I'm doing something wrong in Yelp.js, but I can't be sure because I'm getting a type error that "fetchRestaurants" is not a function in App.js, no matter which way I call it. I think it involves Promises, and I tried using async/await on searchYelp, but this part is all new to me.
Here's Yelp.js:
import axios from "axios";
const KEY = "RwNYGeKdhbfM1bo6O8X04nLNR7sKjIXyAQ-Fo-nz-UdNHtSKDAmHZCc9MSiMAVmNhwKrfcukZ0qlHF1TdVIRSrgak3-oHVNmGD5JPR4ysxhfGd1hgOllt83H1i44X3Yx";
const fetchRestaurants = (term, location, sortBy) => { const corsApiUrl = "https://cors-anywhere.herokuapp.com/"; return () => {
axios
.get(
`${corsApiUrl}https://api.yelp.com/v3/businesses/search?categories=restaurants&location=${location}&term=${term}&sort_by=${sortBy}`,
{
headers: {
Authorization: `Bearer ${KEY}`,
},
}
)
.then(res => res.data.businesses)
.catch(error => console.log(error.response)); }; };
export default fetchRestaurants;
And here's App.js:
import React, { useState } from "react";
import BusinessList from "./BusinessList";
import SearchBar from "./SearchBar";
import Yelp from "./Yelp";
import "./App.css";
const App = props => {
const [businesses, setBusinesses] = useState([]);
const searchYelp = (term, location, sortBy) => {
const businessList = Yelp.fetchRestaurants(term, location, sortBy);
setBusinesses(businessList);
};
return (
<div className="App">
<h1>Ravenous</h1>
<SearchBar searchYelp={searchYelp} />
<BusinessList businesses={businesses} />
</div>
);
};
export default App;
Apologies in advance if this was supposed to be posted somewhere else. Noob probs.
you did not save the response anywhere. .then(res => res.data.businesses) here the response should've been saved somewhere, either a varibale or state. also your function responseble for the axios request doesn't return anything.
It's not an issue with axios itself, but how you use it in your React application.
Yelp.js: fetchRestaurants() should return a proper value (promise in this case) :
const fetchRestaurants = (term, location, sortBy) => {
return axios
.get(url, options)
.then(res => res.data.businesses)
.catch(...)
}
App.js: All API calls should be done using useEffect hook:
useEffect(() => {
Yelp.fetchRestaurants(term, location, sortBy)
.then(businessList => setBusinesses(businessList));
}, [term, location, sortBy]);

I want to set preauthorizeApiKey in swagger-ui-react application auto authorized

I have below code where I have set preauthorizeApiKey and it's working fine and calls to APIs is also working. APIs need header "Authorization: Bearer xxxxxxxxxxx". I had key stored in react store and reading using getToken().
import React from 'react';
import SwaggerUI from 'swagger-ui-react';
import swaggerSpec from '../../swagger.json';
import { getToken } from '../../api/utils'
export const complete=function(swaggerUi)
{
let token = getToken();
swaggerUi.preauthorizeApiKey('bearerAuth', token.Token);
}
const ApiDocs = () => {
return <SwaggerUI spec={swaggerSpec} onComplete={(swaggerUi) => complete(swaggerUi)} />
};
export default ApiDocs;
Below is my route configuration:
<Route path="/api-docs" component={ApiDocs} />
I don't need to click on Authorize button on swagger UI screen and it is auto Authorized. Just wanted to share for any comment/suggestion/improvement.
The onComplete props should be a function. Please see the document here.
import React from "react";
import SwaggerUI from "swagger-ui-react";
import swaggerSpec from "../../swagger.json";
import { getToken } from "../../api/utils";
export const complete = function (swaggerUi) {
const token = getToken();
swaggerUi.preauthorizeApiKey("bearerAuth", token.Token);
};
const ApiDocs = () => {
return <SwaggerUI spec={swaggerSpec} onComplete={complete} />;
};
export default ApiDocs;

Resources