Goal: Fetch data from api then assign it to a state for further processing.
Issue: After setting the data to my useState it is still undefined.
Questions:
How would one solve this problem?
Am I misunderstanding the useState hook?
import "./styles.css";
import axios from "axios";
import { useEffect, useState } from "react";
export default function App() {
const [userData, setUserData] = useState();
const functionz = () => {
return axios
.get("https://randomuser.me/api/")
.then(({ data }) => data.results);
};
useEffect(async () => {
const data = await functionz();
setUserData(data);
}, []);
if (userData) {
console.log(userData);
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Edit to see some magic happen!</h2>
</div>
);
}
You have to make sure your function is returning the axios call. Then await whatever comes out of it in your useEffect. Then proceed to adding it to your state. See example.
import React, { useState, useEffect } from 'react'
import axios from "axios";
const Api = () => {
const [usersData, setUsersData] = useState(null)
const fetchRandomUserData = () => axios.get('the-url')
useEffect(() => {
fetchRandomUserData()
.then(resp => {
setUsersData(resp.data.results)
})
.catch(e => {
console.log('Error: ', e)
})
}, [])
console.log(usersData)
return <div></div>
}
export default Api
Related
I'm trying to pass a JSON object (id) returned from an API call to another component via props and use that object(id) to fetch more data from a different endpoint. The problem is, when i pass the prop using object literal to the api, it gives an error undefined but when i console log the object(id) it works fine. What could be the issue? Just started learning React.
component passing object as prop
import axios from "axios";
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import Cast from "./Cast";
const DetailsView = () => {
const { id } = useParams();
const [details, setDetails] = useState([]);
useEffect(() => {
axios
.get(
`https://api.themoviedb.org/3/movie/${id}?api_key=<<api_key>>&language=en-US`
)
.then((response) => {
setDetails(response.data);
});
}, []);
return (
<div className="w-full h-[650px] text-white">
<<bunch of code>>
<Cast id={details?.id}/>
</div>
);
};
export default DetailsView;
component receiving prop
import React, { useState, useEffect } from "react";
import axios from "axios";
const Cast = (props) => {
const [cast, setCast] = useState([]);
const sid = props.id;
useEffect(() => {
axios
.get(
`https://api.themoviedb.org/3/movie/${sid}/credits?api_key=<<api_key>>&language=en-US`
)
.then((response) => {
setCast(response.data.cast);
console.log(response.data.cast);
});
}, []);
console.log(sid);
return (
<div className="absolute">
{cast && cast.map((item, index) => <p className="">{item.name}</p>)}
<p>{sid}</p>
</div>
);
};
export default Cast;
It doesn't work initially but when I edit the code, since the change is happening live, it fetches the data but when I refresh the page, Axios reports an error 404
xhr.js:220 GET https://api.themoviedb.org/3/movie/**undefined**/credits?api_key=56fbaac7fd77013cc072d285a17ec005&language=en-US 404
Your id property does not exist until the API call is completed, and there is a rerender after setDetails.
You can check if id exists and based on that render your Card component. Also, looks like details is an object not an array, so I changed the useState statement to reflect that.
import axios from "axios";
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import Cast from "./Cast";
const DetailsView = () => {
const { id } = useParams();
const [details, setDetails] = useState({});
useEffect(() => {
axios
.get(
`https://api.themoviedb.org/3/movie/${id}?api_key=<<api_key>>&language=en-US`
)
.then((response) => {
setDetails(response.data);
});
}, []);
return (
<div className="w-full h-[650px] text-white">
<<bunch of code>>
{details?.id && <Cast id={details?.id}/>}
</div>
);
};
export default DetailsView;
Quick Help Needed! I have Two React components Vendors and VendorsList. In Vendors.js Component i have asset.asset_name text rendered in table format. What I want is, When I click on I asset.asset_name, I wanted to pass it's value from Vendors component to VendorsList component. How could I do this?
Here is code for Two Components
Vendors.js
import React, { useEffect, useState } from "react";
import { axios } from "axios";
const Vendors = () => {
const [data, setData] = useState({});
const baseURL =
"http://127.0.0.1:8000/api/business_process/business-impact/business-assets-detail";
useEffect(() => {
axios
.get(baseURL)
.then((response) => {
setData(response.data);
})
.then(
(response) => {},
(err) => {
alert("No Data To Show");
}
)
.catch((err) => {
return false;
});
}, []);
const DisplayData = data.business_assets?.map((asset) => {
return (
<tr>
<td>{asset.business_assets}</td>
<td onClick={() => alert(asset.asset_name)}>{asset.asset_name}</td>
</tr>
);
});
return <div></div>;
};
export default Vendors;
Here is VendorsList.js
import React from "react";
const VendorsList = () => {
return (
<div>
<h1>{foo}</h1>
</div>
);
};
export default VendorsList;
I need asset.asset_name value to be passed to VendorsList when I click on asset.asset_name value from Vendors component
I don't think you're passing the asset_name into your VendorsList component at all. I think the quickest way is to directly render the VendorsList in your Vendors component by putting it in the return of your Vendors component. You would also need something to record what you have clicked so you can use another useState for this. Below is how you'd achieve this:
Modify your Vendor.js to look like this:
import React, { useEffect, useState } from "react";
import { axios } from "axios";
import VendorsList from '<path to your VendorList component>'
const Vendors = () => {
const [data, setData] = useState({});
const [clickedAsset, setClickedAsset] = useState()
const baseURL =
"http://127.0.0.1:8000/api/business_process/business-impact/business-assets-detail";
useEffect(() => {
axios
.get(baseURL)
.then((response) => {
setData(response.data);
})
.then(
(response) => {},
(err) => {
alert("No Data To Show");
}
)
.catch((err) => {
return false;
});
}, []);
const DisplayData = data.business_assets?.map((asset) => {
return (
<tr>
<td>{asset.business_assets}</td>
<td onClick={() => setClickedAsset(asset.asset_name)}>{asset.asset_name}</td>
</tr>
);
});
return (
<div>
<DisplayData/>
<VendorList clickedAssetName={clickedAsset}/>
</div>
);
};
export default Vendors;
Then to use the clickedAssetName that you just passed, access it like this in your VendorsList.js component:
import React from "react";
const VendorsList = ({clickedAssetName}) => {
return (
<div>
<h1>{clickedAssetName}</h1>
</div>
);
};
export default VendorsList;
Im making a project where I fetch an image of a recipe card from https://spoonacular.com and I want it displayed on my react.js app. For some reason I can't get the API data from displaying on the page when I run it. Please help Im really stuck. I keep getting the error that recipeList is undefined in Recipe.js but I thought it was defined?
This is my Home.js:
import React, { useEffect, useState } from "react";
import axios from "axios";
import Recipe from "../components/Recipes";
const URL = `https://api.spoonacular.com/recipes/716429/information?apiKey=${APIKey}&includeNutrition=false`;
function Home() {
const [food, setFood] = useState();
useEffect(() => {
if (food) {
axios
.get(URL)
.then(function (response) {
const recipeList = response.data;
setFood(recipeList);
})
.catch(function (error) {
console.warn(error);
});
}
}, [food]);
return (
<main>
<Recipe recipeList={food} />
</main>
);
}
export default Home;
this is my Recipe.js
import React from "react";
function Recipe({ recipeList }) {
return (
<div className="Recipe">
<div>{recipeList.title}</div>
<img src={recipeList.image} />
</div>
);
}
export default Recipe;
you need initializing empty
const [food, setFood] = useState({});
and in useEffect evaluate if food is empty
useEffect(() => {
const getData=()=>{
axios
.get(URL)
.then(function (response) {
const {data} = response;
setFood(data);
})
.catch(function (error) {
console.warn(error);
});
}
if(!food){ // validate if food is empthy to get data (food)
getData()
}
}, []); // here is not necesary use food, because never happen anything with that variable
The response example can be seen here.
To call that using axios:
import React, { useEffect, useState } from "react";
import axios from "axios";
import Recipe from "../components/Recipes";
const URL = `https://api.spoonacular.com/recipes/716429/information?apiKey=${APIKey}&includeNutrition=false`;
function Home() {
const [food, setFood] = useState({});
useEffect(() => {
// You can add any if-else statement here
// but you can also do the fetch without it
axios
.get(URL)
.then(function (response) {
setFood(response.data);
})
.catch(function (error) {
console.warn(error);
});
}, []);
return (
<main>
<Recipe recipeList={food} />
</main>
);
}
export default Home;
And based on the response, your Recipe.js should working properly.
I'm trying to pass data with Context API to child components. Value is getting undefined upon fetching it from a component.
Component Hierarchy:
passing data to a component MockTable and UsecasePane
MainContent -> MockTable
MainContent -> AddMock -> TabContent -> UsecasePane
=> MockContext.js
import React, { useState, useEffect, createContext } from "react";
import axios from "axios";
export const MockContext = createContext();
// provider
export const MockProvider = (props) => {
const [data, setData] = useState([]);
// data fetch and setting the state
return (
<MockContext.Provider data={[data, setData]}>
{props.children}
</MockContext.Provider>
);
};
Note: I'm getting response from the API.
Now in MainContent, components are encapsulated as follows:
// MainContent.js
import React from "react";
import { MockProvider } from "../MockContext";
const MainContent = () => {
return (
<MockProvider>
<div>
<CustomerTable />
<AddMock />
<MockTable />
</div>
</MockProvider>
);
};
When I try to fetch the data in MockTable or in UseCasePane, value is undefined.
// MockTable.js
import React, { useState, useEffect, useContext } from "react";
import { MockContext } from "./MockContext";
const MockTable = () => {
const [data, setData] = useContext(MockContext);
console.log(data);
// rest of the code
}
Please correct me where I'm going wrong :)
I tried to pass a String as well from the context and fetched in a component like:
return (
<MockContext.Provider data={"Hello"}>
{props.children}
</MockContext.Provider>
);
// in MockTable.js
const value = useContext(MockContext); ==> undefined
The correct prop to pass into the Provider is value, not data. (See: Context.Provider)
import React, { useState, useEffect, createContext } from "react";
import axios from "axios";
export const MockContext = createContext();
// provider
export const MockProvider = (props) => {
const [data, setData] = useState([]);
const fetchData = async () => {
const response = await axios
.get(config.App_URL.getAllRoute, {
params: {
customHostName: config.host,
type: config.type,
},
})
.catch((error) => {
console.error(`Error in fetching the data ${error}`);
});
console.log(response.data);
setData(response.data);
};
useEffect(() => {
fetchData();
}, []);
return (
<MockContext.Provider value={[data, setData]}>
{props.children}
</MockContext.Provider>
);
};
What's wrong with the following component?
Its throws an error while the original class based version with life cycle methods works fine?
import React, { useState, useEffect } from "react";
import axios from "axios";
const NewsHook = ()=> {
const [mount, setMount] = useState(false);
const [news, setNews] = useState([]);
useEffect(() => {
setMount(true);
axios.get('https://hn.algolia.com/api/v1/search?query=react')
.then(result => {
if (mount){
setNews({
news: result.data.hits,
})
}
}
);
return () => {
setMount(false);
}
}, [mount]);
return (
<ul>
{news.map(topic => (
<li key={topic.objectID}>{topic.title}</li>
))}
</ul>
);
}
export default NewsHook
the solution was that the following:
setNews(result.data.hits);
The problem is because the data is fetching. So news will be still null. Either using async to solve the problem or doing in this way :)
import React, { useEffect, useState } from "react";
import axios from "axios";
import "./styles.css";
export default function App() {
const [mount, setMount] = useState(false);
const [news, setNews] = useState([{ new: null }]);
useEffect(() => {
setMount(true);
axios
.get("https://hn.algolia.com/api/v1/search?query=react")
.then(result => {
setNews({ new: result.data.hits });
});
return () => {
setMount(false);
};
}, [mount]);
return (
<div>
<ul>
{news.new == null ? (
<h2>Loading</h2>
) : (
news.new.map(item => {
return <li key={item.objectID}>{item.title}</li>;
})
)}
</ul>
</div>
);
}
it will solve your problem.
Hope it is help :)
you don't need to set a state of mount because the useEffect will work automatically when the component mounts and if you want it to work just ones, you add empty array [] as the second argument
and you have to wrap your Axios request inside useEffect to an async function like that:
import React, { useState, useEffect } from "react";
import axios from "axios";
const NewsHook = ()=> {
const [news, setNews] = useState([]);
useEffect(() => {
const getNews = async () => {
const result = await axios.get('https://hn.algolia.com/api/v1/search?query=react');
setNews({
news: result.data.hits,
})
};
getNews();
}, []);
return (
<ul>
{news.map(topic => (
<li key={topic.objectID}>{topic.title}</li>
))}
</ul>
);
};
export default NewsHook