const [category, setCategory] = useState("general")
const news = await axios.get(`https://newsapi.org/v2/top-headlines?country=in&apiKey=64968be4903a4a979fe05c58a3355a73
&category=${category}`);
**As I am fetching API but its not fetching as is shows an empty array can anyone tell me where I am I going wrong **
You can not use the response of an async function directly in your React functional component. You have to use a state which holds your news. If you call setNews React automatically rerenders your component with the new news data.
export function News() {
const [category, setCategory] = useState("general");
const [news, setNews] = useState([]);
// fetch news everytime the category changes
useEffect(() => {
async function fetchNews() {
try {
const url = `https://newsapi.org/v2/top-headlines?country=in&apiKey=64968be4903a4a979fe05c58a3355a73&category=${category}`;
const response = await axios.get(url);
console.log(response);
setNews(response.data.articles);
} catch (errorWhileFetchingNews) {
console.log("error while fetching news", errorWhileFetchingNews);
}
}
fetchNews();
}, [category]);
// render the news
return (
<div>
{
news.map((article, i) => {
return <div key={i}>{article.title}</div>;
})
}
</div>
);
}
EDIT:
CAUTION: The CORS issues seem to appear only in my codesandbox example. If the example above runs on localhost:3000 in a normal React app (create-react-app) it works like it should. So you might ignore the following description.
Unfortunately the server newsapi.org doesn't send CORS headers. So you are not allowed to call this service directly via AJAX requests (axios, fetch, ...). You either find a way to enable CORS on this site (because you have an API key you may be able to administrate something?) or you find an other service that supports CORS or you have to send your request through a proxy. The proxy/backend then have to run on the same domain (host + port) like your frontend or the proxy must handle all the CORS header stuff. There are also questions on stackoverflow that have the same issue with newsapi.org but I am afraid that there is no easy solution/workaround for this.
I have setup a working example with jsonplaceholder.typicode.com (supports CORS) instead of newsapi.org.
See here: https://codesandbox.io/s/white-wildflower-su5vd?file=/src/News.js
Just in case the example is not reachable anymore, here is the code:
import { useState, useEffect } from "react";
import axios from "axios";
export function News(props) {
const [category, setCategory] = useState("general");
const [news, setNews] = useState([]);
// fetch news everytime the category changes
useEffect(() => {
async function fetchNews() {
try {
const url = "https://jsonplaceholder.typicode.com/comments";
const response = await axios.get(url);
console.log(response);
setNews(response.data);
} catch (errorWhileFetchingNews) {
console.log("error while fetching news", errorWhileFetchingNews);
}
}
fetchNews();
}, [category]);
// render the news
return (
<div>
{
news.map((article) => {
return <div key={article.id}>{article.name}</div>;
})
}
</div>
);
}
Related
I've read several questions here regarding my current difficulty; they also told me the way I was coding it was wrong, and I changed it. However, even after changing I still can't seem to get the proper result.
I'm trying to make a small React HTTP Request app for learning purposes. According to the classes I've been following, I managed to create the json server, setup to watch for the DB.json properly, etc. Now, inside the App.js I'm trying to make the async\await call for listing the products in the console.
First, I had the following error:
"Effect callbacks are synchronous to prevent race conditions. Put the async function inside:"
I fixed it by changing my code. It was triggering a warning and I found out the classes I've been following are a bit outdate. No problem. However, even after changing it I can't view the products I create on db.json. If I go to localhost:3000/products it shows up there (which means things are working).
I believe I'm doing it the right way now, but I still can't seem to figure out why I can't view the data.
Any input is appreciated. Thanks!
ps: I'm just starting with react.
App.Js
import './App.css';
import { useState, useEffect } from "react";
const url="http:/localhost:3000/products";
function App() {
const [products, setProducts] = useState ([]);
useEffect(() => {
const fetchData = async () => {
const data = await fetch(url);
console.log("Data:" + data)
const res = await data.json();
console.log("Res:" + res)
setProducts(res);
}
fetchData();
}, []);
console.log(products);
return (
<div className="App">
<h1>LIsta de produtos</h1>
</div>
);
}
export default App;
The URL you put is missing a "/", Check if the URL is right, rest else seems to be correct, the code below should work.
import "./App.css";
import { useState, useEffect } from "react";
// URL is probably wrong, this is fixed URL
const url = "http://localhost:3000/products";
function App() {
const [products, setProducts] = useState([]);
useEffect(() => {
const fetchData = async () => {
const data = await fetch(url);
console.log("Data:" + data);
const res = await data.json();
console.log("Res:" + res);
setProducts(res);
};
fetchData();
}, []);
console.log(products);
return (
<div className="App">
<h1>LIsta de produtos</h1>
</div>
);
}
export default App;
I'm working on a small react project and using axios interceptors to catch whether I'm in a localhost development environment or on the production deployed website.
What's happening is that when people sign up to my site, they click on the confirmation email link, and land on a certain "state" or whatever you call it or the application where the axios interceptor doesn't know what environment I'm on, and for a split second the wrong api call is made, to the right after it calling the right api uri.
Let me show this with some code:
export const App = () => {
useEffect(() => {
axios.interceptors.request.use((req) => {return { ...req, url: getBaseUri() + req.url
};})}, []);
return (
<div className="App">
<Routes />
</div>
)}
And then the methods:
const devUriBase = "http://localhost:8080";
const prodUriBase = "https://my-website.herokuapp.com";export function getBaseUri() {
return window.location.host.includes("localhost") ? devUriBase : prodUriBase;
}
Then on the verification page component, where I make the api call itself, for a moment the api call is made to the incorrect url so for a split second the component is shown, then it seems the useEffect jumps in and the api call is made again. None of the combinations I tried worked. I tried to make a config component and through children have the axios interceptor, putting this in the index instead, and I don't know what else. I've been struggling with this for 3 days, I thought it was time to ask.
import { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import axios from 'axios';
import { useToken } from '../../auth/useToken';
import { EmailVerificationSuccess } from './EmailVerificationSuccess';
import { EmailVerificationFail } from './EmailVerificationFail';
export const EmailVerificationLandingPage = () => {
const { verificationString } = useParams();
const [, setToken] = useToken();
const [state, setState] = useState('loading');
useEffect(() => {
const loadVerification = async () => {
try {
const response = await axios.put('/api/verify-email', { verificationString });
const { token } = response.data;
setToken(token);
setState('success');
} catch (e) {
setState('error');
}
}
loadVerification();
}, [setToken, verificationString]);
if (state === 'loading') return <p>Cargando...</p>;
if (state === 'error') return <EmailVerificationFail />
return <EmailVerificationSuccess />
I appreciate your help.
This did it.
When you add request interceptors, they are presumed to be asynchronous by default. This can cause a delay in the execution of your axios request when the main thread is blocked (a promise is created under the hood for the interceptor and your request gets put on the bottom of the call stack). If your request interceptors are synchronous you can add a flag to the options object that will tell axios to run the code synchronously and avoid any delays in request execution.
axios.interceptors.request.use(function (config) {
config.headers.test = 'I am only a header!';
return config;
}, null, { synchronous: true });
I've been working on a Next.JS web application for the past couple of days but I've reached a problem. The app has an API call (/api/settings) which returns some settings about the application from the database. Currently, I have a function which returns these settings and access to the first component:
App.getInitialProps = async () => {
const settingsRequest = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/settings`
);
const settingsResponse = await settingsRequest.json();
return { settings: settingsResponse };
};
This does work and I am able to pass in settings to components but there are two problems with this:
I need to nest the prop through many components to reach the components that I need
This request runs every time a page is reloaded/changed
Essentially, I need to create a system that does this:
runs a function in the _app.tsx getInitialProps to check if the data is already in localStorage, if not make the API request and update localStorage
have the localStorage value accessible from a custom hook.
Right now the problem with this is that I do not have access to localStorage from the app.tsx getInitialProps. So if anyone has an alternative to run this function before any of the page loads, please let me know.
Thanks!
I found a solution, it might be a janky solution but I managed to get it working and it might be useful for people trying to achieve something similar:
First we need to create a "manager" for the settings:
export const checkIfSettingsArePresent = () => {
const settings = localStorage.getItem("app_settings");
if (settings) return true;
return false;
};
export const getDataAndUpdateLocalStorage = async () => {
const r = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/settings`);
const response = await r.json();
localStorage.setItem("app_settings", JSON.stringify(response));
};
With that created we can add a UseEffect hook combined with a useState hook that runs our function.
const [doneFirst, setDoneFirst] = useState<boolean>(false);
useEffect(() => {
const settingsPreset = checkIfSettingsArePresent();
if (performance.navigation.type != 1)
if (settingsPreset) return setDoneFirst(true);
const getData = async () => {
await getDataAndUpdateLocalStorage();
setDoneFirst(true);
};
getData();
}, []);
//any other logic
if (!doneFirst) {
return null;
}
The final if statement makes sure to not run anything else before the function.
Now, whenever you hot-reload the page, you will see that the localStorage app_settings is updated/created with the values from the API.
However, to access this more simply from other parts of the app, I created a hook:
import { SettingsType } from "#sharex-server/common";
export default function useSettings() {
const settings = localStorage.getItem("app_settings") || {
name: "ShareX Media Server",
};
//#ts-ignore
return JSON.parse(settings) as SettingsType;
}
Now I can import useSettings from any function and have access to my settings.
I am trying to mock my REST requests for a react/ts project when testing in Storybook using Axios. Even though I am setting the response to an array object, it still seems to be responding with a "Request failed with status code 404" status.
Here is my component making the REST call: TestPrompt.tsx
const onClickHandler = () => {
requestOrMock("http://localhost:9002/projectPlan/projectTasks?project=FAKEWID")
}
Here is the method my TestPrompt component is using to make the request: UtilityFunctions.ts
import axios from 'axios';
export const axiosMock = axios.create();
export const requestOrMock = async (uri: string) => {
const response = axiosMock.get(uri);
return response;
}
Here is my test that is mocking the response: Prompt.stories.tsx
import * as React from "react";
import {storiesOf} from '#storybook/react';
import TestPrompt from "../components/common/Prompt";
import MockAdapter from 'axios-mock-adapter';
import { axiosMock } from "../utils/utilityFunctions";
const mock = new MockAdapter(axiosMock);
const blankPromptRequestUri = "http://localhost:9002/projectPlan/projectTasks?project=FAKEWID";
const footballTeams = [
{
"descriptor": "New England Patriots",
"id": "NewEnglandPatriots"
},
{
"descriptor": "Seattle Seahawks",
"id": "SeattleSeahawks"
}
];
storiesOf('Components/MultiSelect', module)
.add('Prompt1', () => {
mock.onGet(blankPromptRequestUri).reply(200, footballTeams);
return (
<TestPrompt/>
);
})
When I click on this component in storybook, it sends out the request to the designated url, but it gets the 404 response rather than the footballTeams object I have specified. Any idea what I have done wrong? Thanks for your help.
If I get your problem correctly, you need to call onGet() of mock to setup the mock end point and then send a request to that end point.
mock.onGet("/teams").reply(200, footballTeams);
storiesOf('Components/MultiSelect', module)
.add('Prompt1', () => {
axios.get("/teams")
.then(res => console.log(res.data))
return (
<TestPrompt/>
);
})
The requests that were being made were being made relative to the host, so rather than "http://localhost:9002/projectPlan/projectTasks?project=FAKEWID" being sent, it was actually "/projectPlan/projectTasks?project=FAKEWID". It is likely that you will only need to pass in the routes here.
I am making an app to fetch data from a recipeDB API, and right now I need to click on the search button have it console.log some data. Right now it is giving me a network error when attempting to fetch the resource. I have my code setup like this
import React, { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const API_ID = "0fc98505";
const API_KEY = "5e81ce76845f459b53f9fbe775e81e53";
const [recipes, setRecipes] = useState([]);
const getRecipes = async () => {
const response = await fetch(
`https://api.edamam.com/search?q=chicken&app_id=${API_ID}&app_key=${API_KEY}`
);
const data = await response.json();
setRecipes(data)
console.log(data);
};
return (
<div className="App">
<button onClick={getRecipes}>Retrive data</button>
</div>
);
}
If there is a network error, this means that your request is executed. I think the error here lies in your APP_ID and API_KEY. Another reason might be CORS. For more details visit MDN page.
Also you can check out «Network» tab in your developer tools(F12) where error description is sometimes shown in response body.