Fetching random data from API on button click - React - javascript

When request is sent, response is always the same on page reload in Chrome but random (as it should be) in FireFox. On button click data is always the same after page reload.
I want to make a request on each button click to store different data in the state hook.
I also tried it in vanilla js and response is the same as well.
What is causing data to always be the same and not random on request?
I will store previously fetched data in the state but first have to figure out why is it always the same, I would appreciate any help as I'm new to these api calls and react as well.
App.js:
import FetchColor from './common/FetchColor';
import ColorList from './components/ColorList';
import { useEffect, useState } from 'react';
function App() {
const [colorData, changeColor] = useState('');
const changeColorHandler = () => {
FetchColor(changeColor);
};
useEffect(() => {
FetchColor(changeColor);
}, []);
return (
<div className='App'>
<button onClick={changeColorHandler}>
{colorData ? colorData.tags[0].name : 'Change Color'}
</button>
<ColorList color={colorData} />
</div>
);
}
export default App;
FetchColor.js:
const FetchColor = async (changeColor) => {
const response = await fetch('https://www.colr.org/json/color/random');
const data = await response.json();
const [color] = data.colors;
changeColor(color);
};
export default FetchColor;
Vanilla JavaScript script.js:
const fetchButton = document.getElementById('fetch-api');
fetchButton.addEventListener('click', fetchColorFunc);
async function fetchColorFunc() {
const response = await fetch('https://www.colr.org/json/color/random');
console.log(`Response: ${response}`);
const data = await response.json();
console.log(`Data: ${data}`);
}

This is most likely due to caching. If you look at the requests in Chrome's Network panel of the Developer Tools, you should see that the requests are cached and therefore always return the same value.
Fetch optionally takes an init object containing custom settings that will be applied to the request, including cache. For example, you can pass cache: "no-cache" or cache: "no-store" to bypass caching (see documentation for details and differences) and you will get random results with each request.
See the following snippet as an example:
async function fetchColorFunc() {
const response = await fetch('https://www.colr.org/json/color/random', { cache: "no-cache" });
const data = await response.json();
console.log(`Data: ${JSON.stringify(data)}`);
}
fetchColorFunc();

Chrome caches the request. You can see this, if you open the developer tools and check on the network tab. You will see, that all later calls are fetched from disk cache.
You can either add some random query to the url
const response = await fetch('https://www.colr.org/json/color/random?t='+Date.now());
or you can add a cache-control header with value no-cache.
const response = await fetch('https://www.colr.org/json/color/random', { headers : {"cache-control": "no-cache"}});
But that will trigger a preflight request and requires the server to allow CORS from your origin.

Related

How do I get my layout component to remain static in Next13 app folder

I am trying to create a layout component that fetches its own data, I have tried adding the cache: 'force-cache' to the fetch but every time I update my CMS content and refresh my page the new content is loaded. Here is an example of my code:
const getLayoutData = async () => {
const response = await fetch(
`https://cdn.contentful.com/spaces/${
process.env.CONTENTFUL_SPACE_ID
}/environments/${
process.env.CONTENTFUL_ENVIRONMENT || "master"
}/entries/${fieldId}?access_token=${process.env.CONTENTFUL_ACCESS_TOKEN}`,
{
cache: "force-cache",
}
);
const {entryTitle, ...headerData} = await response.json();
return { headerData };
}
export default async function Layout() {
const data = await getLayoutData();
...
You can use the getStaticProps() function to fetch data at build time and make it available to your component as a prop. This way, the data will be pre-rendered on the server and will not change when the user refreshes the page:
import getLayoutData from './getLayoutData';
export async function getStaticProps() {
const data = await getLayoutData();
return { props: { data } };
}
export default function Layout({ data }) {
// Use data in your component
...
}
Alternatively you could use getServerSideProps(), it runs on the server at request time instead of build time. I would recommend that if you have dynamic data that changes frequently:
import getLayoutData from './getLayoutData';
export async function getServerSideProps(context) {
const data = await getLayoutData();
return { props: { data } };
}
export default function Layout({ data }) {
// Use data in your component
...
}
By default, Next.js automatically does static fetches. This means that the data will be fetched at build time, cached, and reused on each request. As a developer, you have control over how the static data is cached and revalidated.
Refer to the docs - https://beta.nextjs.org/docs/data-fetching/fundamentals
Also, this will work in production mode. So, make sure you are using next build && next start and not next dev.
In case you are fetching data from same URL anywhere else, the cache might be getting updated. As Next.js also does request deduplication built into the fetch function itself.

Error message : SyntaxError: Unexpected token < in JSON at position 0

i was trying to fetch a data for a project but everytime i'm converting the fetch data to json it returns me
SyntaxError: Unexpected token < in JSON at position 0
i don't understand why it's showing me this
import React,{useContext,useState,useEffect} from 'react'
const url = 'www.thecocktaildb.com/api/json/v1/1/search.php?s='
export default function AppProvider({children}) {
const [loading,setLoading] = useState(true)
const [searchTerm,setSearchTerm] = useState('a')
//set it as 'a' for suggestion at search bar at beginning.
const [cocktails,setCocktails] = useState([])
const fetchUrl = async ()=>{
setLoading(true)
try {
const response = await fetch(`${url}${searchTerm}`)
//(${url}${searchterm} helps me to fetch data at first with names that starts with 'a' for suggestion///
const data = await response.json()
setLoading(false)
} catch (error) {
console.log(error)
}
}
useEffect(()=>{
fetchUrl()
},[searchTerm])
please visit the API page from the URL & see if there's an issue with the data. the data is not fetching. what's the issue?
Link
Doing
fetch('www.thecocktaildb.com/')
will fetch not that website, but that path relative to the current path. For example, doing so here on Stack Overflow results in the URL being fetched being
https://stackoverflow.com/questions/72914244/www.thecocktaildb.com/
which, of course, doesn't exist - and presumably that URL doesn't exist on your site either.
Use the full path.
const url = 'https://www.thecocktaildb.com/api/json/v1/1/search.php?s='
I'd also recommend only calling the API when searchTerm isn't empty, and perhaps add a debounce of a few hundred milliseconds so as not to call it too often and to keep the client from being blocked.

Axios is not getting response on first load

I am new in React JS and trying to get the data inside useEffect and I have a separate function for my api, but when I check the data.next in console.log there is no data in the first load but after adding few changes it works fine but still has an error when I refresh the page. Also, I noticed when I tried to console.log inside of function where the Axios or api declared, there's already a data in the first load of an application. Did anyone encounter this issue? Or my approach is wrong?
Here are my codes
/src/App.js
useEffect(async () => {
const res = await service.apiPokemon.fetchAll();
console.log(res.data.next)
}, []);
/src/api/pokemon.js
import axios from 'axios';
const URL = 'https://pokeapi.co/api/v2/pokemon';
export const fetchAll = async () => {
try {
const res = await axios.get(URL);
console.log(res.data.next);
return res;
} catch (error) {
console.log(error);
};
};
This is a very common problem. Your content is loaded before fetching the data. To solve this, you can add a condition to not render your content until you get the data:
let [pokemonsList, setPokemonsList] = useState([])
// Your useEffect hook to fetch data on mount
return (
{ pokemonsList.lenght > 0 && // If you are sure you'll receive pokemons
<div> {pokemonList.map((pokemon) => (
<p> {pokemon.name} </p>
)} </div>
}
)
Now, you'll only see the names of the pokemons when you have the list.
You can also add a loading message in case the response takes time with Redux and selectors.

API calls served over HTTP instead of HTTPs results in error in React/Axios

I'm using an API to fetch movie data using axios in my React app. While this works in localhost, I've recently uploaded this to github pages where it no longer works and it results in this error.
"Mixed content: load all resources via HTTPS to improve the security of your site"
My code is shown below:
const fetchItems = async () => {
const result = await axios(
`http://www.omdbapi.com/?s=${searchTitle}&type=movie&page=${searchPage}&y=${searchYear}&apikey=myapikeyhere`
);
if (result.data.totalResults) {
console.log("fetching data:", result.data.Search);
setQueryLength(result.data.Search.length);
setMovieQuery(result.data.Search);
} else {
setMovieQuery([]);
setQueryLength(0);
}
setLoading(false);
};
This code is contained within a useEffect hook, when a user enters data into a text field movies are supposed to appear corresponding to the movie title. Nothing is being printed in my github pages site and I'm getting the error detailed above. I've never actually encountered this error before and I look forward to getting some feedback
You have to write https and not http
const result = await axios(
`https://www.omdbapi.com/?s=${searchTitle}&type=movie&page=${searchPage}&y=${searchYear}&apikey=myapikeyhere`
);
You need to use https in your endpoint link
const fetchItems = async () => {
const result = await axios(
`https://www.omdbapi.com/?s=${searchTitle}&type=movie&page=${searchPage}&y=${searchYear}&apikey=myapikeyhere`
);
if (result.data.totalResults) {
console.log("fetching data:", result.data.Search);
setQueryLength(result.data.Search.length);
setMovieQuery(result.data.Search);
} else {
setMovieQuery([]);
setQueryLength(0);
}
setLoading(false);
};

How to use AsyncData with Promise.all to get data from multiple api's works client side but causes nginx to 504

I'm currently converting a vue application to use the NUXT framework. To add support for SSR to my application and have come across the following issue when trying to use asyncData with multiple data sources on a single page.
I'm trying to setup asyncData to get data from 2 separate data sources that are required for the page to work. Now the code works on the client-side when the Promise.all resolves it gets both sets of data. However, on the server-side the promises when console.log the promises are both pending and causes Nginx to timeout and give a 504 bad gateway error.
I have tried to get this to work use async/await and promise.all with no avail. see code samples for both below.
Import functions getData and getJsonFile are both using Axios and returning resolved promises with objects of data.
// Using async/await
export default {
async asyncData(context) {
const nameData = await getData('getInformationByNames', {
names: [context.params.name],
referingPage: `https://local.test.com${context.route.fullPath}`
});
const content = await getJsonFile(
`/data/pages/user/${context.params.id}`
);
return {
names: nameData,
content
};
}
}
// Using Promise.all
export default {
async asyncData(context) {
const [nameData, content] = await Promise.all([
getData('getInformationByNames', {
names: [context.params.name],
referingPage: `https://local.test.com${context.route.fullPath}`
}),
getJsonFile(`/data/pages/user/${context.params.id}`)
]);
return {
names: nameData,
content
};
}
}
// getJsonFile
import axios from 'axios';
import replaceStringTokens from '#/scripts/helpers/replaceStringTokens';
export default function getJsonFile(path, redirect = true) {
const jsonFilePath = `${path}.json`;
return axios.get(jsonFilePath).then((response) => {
if (typeof response.data === 'object') {
return replaceStringTokens(response.data);
}
return false;
});
}
// getData
import axios from 'axios';
import getUserDevice from '#/scripts/helpers/getUserDevice';
// require php-serialize node package to serialize the data like PHP would for the api endpoint.
const Serialize = require('php-serialize');
export default function getData(action, data) {
const dataApiAddress = '/api/getData.php';
const dataToPass = data || {};
// all actions available on the api will need to know the users device so add it to the data.
dataToPass.userDevice = getUserDevice();
// package the data like the api expects to receive it
const serializedAndEncodedData = encodeURIComponent(
Serialize.serialize(dataToPass)
);
const axiosParams = {
action,
data: serializedAndEncodedData
};
return axios
.get(dataApiAddress, {
params: axiosParams
})
.then((response) => {
return response.data.data;
})
.catch((error) => {
console.log(error);
return false;
});
}
I would expect that the promises resolve and both sets of data are returned an available for the page to use on both the client and server-side.
Is there a better way to get multiple sets of data or a way to debug the server-side so that I can see what is causing the promises to not resolve on the server?
Fixed the issue the problem was with some discrepancies in the data being queried on the API. The data in the database was using an uppercase letter at the start that must have been input incorrectly. So this was causing the promise to not resolve due to the API sending a query for the lowercase version and in turn causing Nginx to timeout.

Categories

Resources