DGB :
I have a function that fetches from a url in React
const DataContextProvider = (props) => {
const [isLoading, setLoading] = useState(false);
const [cocktails, setCocktails] = useState([]);
useEffect(() => {
const fetchCocktailList = async () => {
const baseUrl = 'https://www.thecocktaildb.com/api/json/v1/1/';
setLoading(true);
try {
const res = await fetch(`${baseUrl}search.php?s=margarita`);
const data = await res.json();
console.log(data);
setCocktails(data.drinks);
setLoading(false);
} catch (err) {
console.log('Error fetching data');
setLoading(false);
}
};
fetchCocktailList();
}, []);
How I'm mapping data so far.
const DrinkList = () => {
const { cocktails } = useContext(DataContext);
return (
<div className='drink-list-wrapper'>
{cocktails.length > 0 &&
cocktails.map((drink) => {
return <DrinkItem drink={drink} key={drink.idDrink} />;
})}
</div>
);
};
However I want to fetch from this url also ${baseUrl}search.php?s=martini
I would like a good clean way to do this and set my state to both of the returned data.
jsejcksn :
Here's a method which will let you specify the cocktail names as dependencies to the useEffect
so you can store them in your state and fetch new drink lists if you want new recipes. If not, it'll just be a static state variable.
- I've also added another state variable
errorMessage
which you use to pass an error message in the case of failure. - Also, you should include the appropriate dependencies in your
useEffect
hook. ThesetState
functions returned by calls touseState
are stable and won't trigger a re-run of the effect, and thecocktailNames
variable won't trigger a re-run unless you update it with new things to fetch.
const DataContextProvider = (props) => {
const [isLoading, setLoading] = useState(false);
const [cocktails, setCocktails] = useState([]);
const [errorMessage, setErrorMessage] = useState(''); // holds an error message in case the network request dosn't succeed
const [cocktailNames, setCocktailNames] = useState(['margarita', 'martini']); // the search queries for the `s` parameter at your API endpoint
useEffect(() => {
const fetchCocktailLists = async (...cocktailNames) => {
const fetchCocktailList = async (cocktailName) => {
const baseUrl = 'https://www.thecocktaildb.com/api/json/v1/1/search.php';
const url = new URL(baseUrl);
const params = new URLSearchParams({s: cocktailName});
url.search = params.toString(); // -> '?s=cocktailName'
const res = await fetch(url.href); // -> 'https://www.thecocktaildb.com/api/json/v1/1/search.php?s=cocktailName'
const data = await res.json();
const {drinks: drinkList} = data; // destructured form of: const drinkList = data.drinks;
return drinkList;
};
setLoading(true);
try {
const promises = [];
for (const cocktailName of cocktailNames) {
promises.push(fetchCocktailList(cocktailName));
}
const drinkLists = await Promise.all(promises); // -> [[drink1, drink2], [drink3, drink4]]
const allDrinks = drinkLists.flat(1); // -> [drink1, drink2, drink3, drink4]
setCocktails(allDrinks);
}
catch (err) {
setErrorMessage(err.message /* or whatever custom message you want */);
}
setLoading(false);
};
fetchCocktailList(...cocktailNames);
}, [cocktailNames, setCocktails, setErrorMessage, setLoading]);
};