I have an array full of user data I'm mapping though to display its information, and I'd like to have a button for each watchlist that deletes that watchlist (the backend already works I tested the deleteWatchlist
function with the string value of an existing watchlist). My problem is that I get the name of the watchlist I need after mapping through the first array.
How do I set the state of the watchlistName for each watchlist?
import axios from "axios";
import { useSession } from "next-auth/react";
import React, { useState } from "react";
import useSWR from "swr";
import CoinInUserProfile from "./CoinInUserProfile";
const fetcher = (...args) => fetch(...args).then((res) => res.json());
function WatchlistContainer() {
const { data: session } = useSession();
const { data: userData, userError } = useSWR(
`http://localhost:5000/api/users/${session?.id}`,
fetcher
);
const [watchlistName, setWatchlistName] = useState();
const deleteWatchlist = async () => {
try {
const res = await axios({
url: `http://localhost:5000/api/users/${session?.id}/deletewatchlist`,
method: "PUT",
data: {
watchlistName: watchlistName,
},
});
} catch (error) {
console.log(error);
}
};
if (userError) return <div>failed</div>;
if (!userData) return <div>loading data...</div>;
console.log(userData);
return (
<div className="flex flex-col">
{userData.watchlists.map((i) => (
<div key={i._id} className="flex flex-col bg-blue-200 m-1">
<p className="text-2xl text-blue-600">{i.watchlistName}</p>
<button type="button" onClick={deleteWatchlist}>
delete
</button>
{i.coins[0].coin.map((coin) => {
return (
<div>
{/* <p key={coin.coinID}>{coin.coinID}</p> */}
<CoinInUserProfile
coinID={coin.coinID}
name={coin.name}
symbol={coin.symbol}
watchlistName={i.watchlistName}
/>
</div>
);
})}
</div>
))}
</div>
);
}
export default WatchlistContainer;
CodePudding user response:
You needn't use state for this in your dynamically rendered component on each iteration pass the current watchlist (i.watchlistName
) into the function as a parameter. To do this update your code as follows:
NOTE: Also note that async functions in a syncronous context returns a promise.
deleteWatchList
const deleteWatchlist = async (watchlistName) => {
try {
const res = await axios({
url: `http://localhost:5000/api/users/${session?.id}/deletewatchlist`,
method: "PUT",
data: { watchlistName }, // variable name same as key name can be used this way
});
} catch (error) {
console.log(error);
}
};
delete button
<button type="button" onClick={()=>deleteWatchlist(i.watchlistName)}>
delete
</button>
If it so happens that react does not trigger a re-render on the axios
API call response add the following code to the deleteWatchList
function:
const deleteWatchlist = async () => {
try {
const res = await axios({
url: `http://localhost:5000/api/users/${session?.id}/deletewatchlist`,
method: "PUT",
data: {
watchlistName: watchlistName,
},
});
// Code to Add
res.then(response=>{
// pull the deleted watchlist in the backend from the selected `user.watchLists` object in the current session.
})
// Code to Add
} catch (error) {
console.log(error);
}
};
Recommendation on Rest API endpoints
Rest API is a semantic model for very specific purposes, this is so that one endpoint represents a
CRUD
(Create, Retrieve, Update, Delete).Instead of exposing the endpoint as
http://localhost:5000/api/users/${session?.id}/deletewatchlist
using aPOST
update your API to accept calls on the 'DELETE' method.And update the endpoint to
http://localhost:5000/api/userwahtchlist
.Make the session.id the cookie and retreive the cookie on the request object in your web api. (will be something like
req.cookie
if you are perhaps usingexpress
.