I am new to React.
I am trying to run a fetch call to get some data when my react page loads. I am not sure I am calling the event correctly though.
Here is how I am calling it:
export default function GetRecipe(props) {
let { name } = useParams()
const [searchQuery, setSearchQuery] = useState('')
const [recipeName, setRecipeName] = useState('')
const [methodStepsList, setMethodStepsList] = useState([])
const [ingredients, setIngredients] = useState([])
const retrieveRecipe = function (e) {
console.log('getting recipe')
e.preventDefault()
console.log(searchQuery.length)
let queryString
if (searchQuery.length) {
queryString = `http://localhost:3001/getbasicrecipe/?name=${searchQuery}`
} else {
queryString = `http://localhost:3001/getbasicrecipe/?name=${name}`
}
fetch(queryString, {
method: 'GET',
headers: { 'Content-type': 'application/json' },
})
.then((resp) => resp.json())
.then((json) => {
console.log(json)
let result = json
let recipeName = result[0].recipe_name
let recipeMethod = result[0].recipe_method.split(/\r?\n/)
console.log(recipeMethod)
setRecipeName(recipeName)
setMethodStepsList(recipeMethod)
setIngredients(json)
})
}
return (
<div>
<div className="recipe-form-container">
<form className="recipe-form">
[...]
</div>
</form>
</div>
</div>
)
I read about componentDidMount() but could not figure out how to include it in my code.
Thanks!
If you are using a class component then, as you mentioned you can use the componentDidMount() lifecycle method like this:
componentDidMount() {
// Runs after the first render() lifecycle
retrieveRecipe();
}
...
render(){
...
}
Docs: https://reactjs.org/docs/state-and-lifecycle.html#adding-lifecycle-methods-to-a-class
However if you are using a function component you should use instead the useEffect hook like this:
useEffect(() => {
retrieveRecipe();
}, []); // by using an empty array as dependency this useEffect will act as the componentDidMount function
...
return (
...
)
Docs: https://reactjs.org/docs/hooks-effect.html
If you are using Class based component
componentDidMount(){
//Your code here
}
render(){
return ...
}
If using function component
useEffet(()=>{
//your code here
}, [])
return (...)
this is a classic case of using useEffect hook -
as in before the return function use -
useEffect(()=>{ retrieveRecipe(); },[]);
it comes instead of componentDidMount
I recommend to play a bit with react.js tutorial to get the hang of it before creating your own projects.
import React, { useEffect } from "react";
function YourComponent() {
useEffect(() => {
retrieveRecipie(e).then((res)=>{
console.log(res);
}
)
}, []);
return (
<div></div>
);
}
export default YourComponent;
mak you retrieveRecipie function
const retrieveRecipie= (yourParams) => {
return fetch(
`URL from where you are fetching data`,
{
method: "GET",
headers: {
Accept: "application/json",
"Content-type": "application/json",
},
body: JSON.stringify(yourParams),
}
)
.then((response) => {
return response.json();
})
.catch((err) => {
console.log(err);
});
};
As you are using Functional Component of React JS, you don't need to handle the component lifecycle method manually. For functional component, there is useEffect hook which will handle the lifecycle of the component.
import React, { useEffect } from 'react';
export default function GetRecipe(props) {
useEffect(() => {
retrieveRecipe();
},[]);
return <></>;
}
The above code will call the retrieveRecipe function only once after rendering this component.
Related
I'm using react query to fetch data to the component.i have a requiremnt to do only first time the component renders.(Set a Default value)So I thought to use fetch data of the useQuery hook inside a useEffect.But it didn't work.
Here is my code...
export default function Header() {
.
.
.
//Here i'm using a custom hook
const { data: workSpaceArray } = useWorkspacesByUserData(onFetchWorkspaceSuccess, onFetchWorkspaceError);
useEffect(() => {
const defaultWorkspaceItem = workSpaceArray?.data.info.workspaces.filter(workspace => workspace.name === workSpaceArray?.data.info.default_workspace_id);
localStorage.removeItem(USER_WORKSPACE);
localStorage.setItem(USER_WORKSPACE, JSON.stringify(defaultWorkspaceItem[0]));
setSelectedWorkspaceValue(defaultWorkspaceItem[0].name)
}, []);
return(
...
);
}
Inside the custom hook...
import { useQuery, useMutation } from 'react-query'
import { protectedRequest } from '../utils/axios-utils'
import { ResponseHandler } from "./ResponseHandler"
const fetchWorkspacesByUserId = async () => {
const response = await protectedRequest({ url: '/workspace/load' });
return ResponseHandler(response);
}
export const useWorkspacesByUserData = (onSuccess, onError) => {
return useQuery('fetch-workspaces-by-user', fetchWorkspacesByUserId,
{
onSuccess,
onError,
staleTime: 120000,
})
}
The error I'm getting.....
Can anybody give me help to fix this issue? Thank you!
Thank you all who looked into this problem. I was able to figure it out by using refetch inside useEffect.
export default function Header() {
.
.
.
//Here i'm using a custom hook
const { data: workSpaceArray, refetch } = useWorkspacesByUserData(onFetchWorkspaceSuccess, onFetchWorkspaceError);
useEffect(() => {
refetch();
const defaultWorkspaceItem = workSpaceArray?.data.info.workspaces.filter(workspace => workspace.name === workSpaceArray?.data.info.default_workspace_id);
localStorage.removeItem(USER_WORKSPACE);
localStorage.setItem(USER_WORKSPACE, JSON.stringify(defaultWorkspaceItem[0]));
setSelectedWorkspaceValue(defaultWorkspaceItem[0].name)
}, []);
return(
...
);
}
I want to fetch an image url to use as the value for the src tag
<img
src={getAircraftImage(foundFlight.aircraft.reg)}
alt="Aircraft"
className="rounded-md w-24 h-12"
/>
function getAircraftImage(reg: string | undefined): string {
let imageUrl;
const options = {
method: "GET",
url: `https://aerodatabox.p.rapidapi.com/aircrafts/reg/${reg}/image/beta`,
headers: {
"X-RapidAPI-Key": "6445ce28c1msh4b2afb9dc1a38bbp17a68bjsn97511bcb4bbf",
"X-RapidAPI-Host": "aerodatabox.p.rapidapi.com",
},
};
axios
.request(options)
.then(function (response) {
imageUrl = response.data.url;
})
.catch(function (error) {
console.error(error);
});
return imageUrl;
}
Problem The Api is not that fast. When i load the image only the alt tag is shown. I have seen in multiple websites a way to show a fallback image as the request is made then show the correct image after but i dont know how to implement it. How do i accomplish that?
As said in the comments: Just use hooks. useEffect to properly execute the request, useState to store the result and render conditionally. You may want to use this hook combination in any scenario where you need to do a request to an external API. As a code example, for a simple component:
import React, { useEffect, useState} from 'react';
import axios from 'axios';
const MyComponent = () => {
// create state of loading, but also state for data
const [loading, setLoading] = useState(true);
const [data, setData] = useState([])
// useEffect to execute request
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
// gets response and saves data into 'data' state
const {data: response} = await axios.get('/stuff/to/fetch');
setData(response);
} catch (error) {
console.error(error.message);
}
setLoading(false);
}
fetchData();
}, []);
// conditional rendering if already loaded
return (
<div>
{loading && <div>Loading</div>}
{!loading && (
<div>
<h2>Doing stuff with data</h2>
{data.map(item => (<span>{item.name}</span>))}
</div>
)}
</div>
)
}
export default MyComponent;
Source: https://dev.to/darkmavis1980/fetching-data-with-react-hooks-and-axios-114h
I want to fetch data from an API and then print it out or to display it in the return statement from my react compenent so I can have a p element that have data fetched from the api in it.
The problem is that the usestate dont get updated
The component code
import React, { useEffect } from "react"
import { newsComponentService } from "../services/newsComponentService";
const NewsComponent = () => {
const [newsComponentData, setNewsComponentData] = React.useState({});
const componentData = React.useRef("");
async function newsComponentHandler() {
let res = await newsComponentService();
//console.log(res);
setNewsComponentData(res);
//console.log(res);
}
useEffect(() => {
newsComponentHandler();
//setNewsComponentData(res);
}, [setNewsComponentData]);
console.log(newsComponentData["data"]);
return (
<p>{newsComponentData["data"]}</p>
)
}
export default NewsComponent;
The api service code
export async function newsComponentService(){
const response = await fetch("api/news-categories/1", {
method: 'GET',
headers: {
'Accept': 'application/json',
},
});
let resJson = await response.json();
//console.log(resJson);
return resJson;
}
I think the issue could be with the async behavior of the JS.
import React, { useEffect } from "react"
import { newsComponentService } from "../services/newsComponentService";
const NewsComponent = () => {
const [newsComponentData, setNewsComponentData] = React.useState({});
const componentData = React.useRef("");
useEffect(() => {
const newsComponentHandler = async () => {
let res = await newsComponentService();
setNewsComponentData(res);
}
newsComponentHandler();
}, [setNewsComponentData]);
console.log(newsComponentData["data"]);
return (
<p>{newsComponentData["data"]}</p>
)
}
export default NewsComponent;
PS. As a good practice, please put the API fetching in try-catch block in newsComponentService.js
I am fetching data in my react component
import React, { useState, useEffect } from 'react';
import { fetchBookData } from './bookData';
import "./App.css";
export default function Books ({ books }) {
const [payload, setPayload] = useState(null)
fetchBookData(books).then((payload) => setPayload(payload));
return (
<div className="App">
<h1>Hello</h1>
</div>
);
}
Here is the fetch function itself
const dev = process.env.NODE_ENV !== 'production';
const server = dev ? 'http://localhost:3001' : 'https://your_deployment.server.com';
// later definable for developement, test, production
export const fetchBookData = (books) => {
const options = {
method: `GET`,
headers: {
accept: 'application/json',
},
};
return fetch(`${server}/books`, options)
.then((response) => {
if(response.ok){
return response.json()
}
throw new Error('Api is not available')
})
.catch(error => {
console.error('Error fetching data in book data: ', error)
})
}
But when I start the server fetch runs in a loop, component making endless get requests to the server. I tried to wrap it in a useEffect, but didn't work. Fetch should run once on load
If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. More
example (codesandbox)
export default function App({books}) {
const [payload, setPayload] = useState(null);
useEffect(() => {
fetchBookData(books).then((payload) => setPayload(payload));
}, [books]);
if (!payload) {
return <h1>Loading...</h1>;
}
return (
<div className="App">
<h1>{payload.title}</h1>
</div>
);
}
I have an array of Names(Commented in code):=
export default Main_homepage = (props) => {
var Names = []
useEffect(() => {
fetch('https://www.amrutras.com/Items.php')
.then((response) => response.json())
.then((responseJson) => {
{
Names = responseJson //***Names Array***
console.log(Names[0].ID) //****Its working, I am getting outpu for this in console
console.log(Names[0].Name)
}
})
.catch((error) => {
console.error(error)
})
})
return(
<View>{console.log(Names[0].ID)}</View> //****Its not working.
)
}
But when I am trying to access outside of the use effect it's not working.
In short, I am trying to access the response array in JSX.
As suggested by Praveen Kumar sir, utilize useState hook.
Here is the Full Working Example: Expo Snack
import React, { useEffect, useState } from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
export default App = (props) => {
const [names, setNames] = useState([]);
useEffect(() => {
fetch('https://www.amrutras.com/Items.php')
.then((response) => response.json())
.then((responseJson) => {
{
console.log(responseJson);
setNames(responseJson); //***Names Array***
}
})
.catch((error) => {
console.error(error);
});
}, []);
return (
<View style={{ marginTop: Constants.statusBarHeight }}>
<Text>{JSON.stringify(names)}</Text>
</View>
);
};
So this is an asynchronous call and it will not work because after the return statement is sent out, the value gets changed.
Change Names into a state hook - Using the State Hook:
// Remove this
// var Names = []
// Replace with:
const [Names, setNames] = useState([]);
And when you're updating, use setNames:
// Remove this inside the promise
// Names = responseJson
// Replace with the following:
setNames(Names);
If you want to understand what an asynchronous call, read more at How do I return the response from an asynchronous call?