userData is a function that receives user data from an API using getUserByChainAccount. getUserByChainAccount requires a username, which in this case is dynamically retrieved from buyer.
I'm interested in avatar , but I keep getting the following error Unhandled Runtime Error ReferenceError: avatar is not defined
function UserTransactionsComponent() {
const [sales, setSales] = useState();
useEffect(() => {
async function fetchData() {
const res = await fetch(
'https://proton.api.atomicassets.io/atomicmarket/v1/sales'
);
const { data } = await res.json();
setSales(data);
}
fetchData();
}, []);
if (!sales) {
return (
<div>
<Spinner />
</div>
);
}
return (
<PageLayout>
<ul>
{sales.map((result) => {
const {
sale_id,
buyer,
seller,
listing_price,
listing_symbol,
created_at_time,
} = result;
const userData = async (buyer) => {
const user = await proton.getUserByChainAccount(buyer);
const { name, avatar } = user;
};
function HandleBuyerClick() {
window.location = '/user/' + buyer;
}
function HandleSellerClick() {
window.location = '/user/' + seller;
}
if (buyer !== null) {
return (
<Card>
<li key={sale_id}>
<h3>
<Transaction>
{avatar}
<Button onClick={HandleSellerClick}>{seller}</Button>
</Transaction>{' '}
just sold item number
<Transaction>
<Button>{sale_id}</Button>
</Transaction>{' '}
to{' '}
<Transaction>
<Button onClick={HandleBuyerClick}>{buyer}</Button>
</Transaction>{' '}
for <Transaction>{formatNumber(listing_price)}</Transaction>{' '}
{listing_symbol} at {parseTimestampJM(created_at_time)}
</h3>
</li>
</Card>
);
}
})}
</ul>
</PageLayout>
);
}
export default UserTransactionsComponent;
Making an API request during rendering is a famously bad idea. React might re-render for a variety of reasons, such as this component or any parent component updating its state. It would be silly to re-request the same API results over and over and over on every render. Not to mention that trying to shoehorn asynchronous operations into a render operation is going to be difficult and buggy.
Requests like that should be made when the component is loaded and the results should be stored in state.
In this case your best bet is probably to make an entirely separate component to render within the .map() operation, and pass that component what it needs to make the API request. For example, consider a .map() like this:
{sales.map((result) => {
return <SomeOtherComponent result={result} />
})}
Then within that component you would handle your API call and manage the state of the result of that call. For example, within SomeOtherComponent you might do this:
const {
sale_id,
buyer,
seller,
listing_price,
listing_symbol,
created_at_time,
} = props.result;
const [avatar, setAvatar] = useState(''); // <-- define the state here
useEffect(() => {
const userData = async (buyer) => {
const user = await proton.getUserByChainAccount(buyer);
const { name, avatar } = user;
setAvatar(avatar); // <--- update the state here
};
userData();
}, []);
// define your click handlers as you already do here
// return your JSX markup as you already do here