The problem I'm dealing with is TypeError: t.map is not a function I'm trying to map my array of jsons to the React components to render them with props.
function App() {
const charts = renderUserProjects();
return(
<div className="app-container">
<h1 className="app-title">Welcome back! Here are your trackings: </h1>
<div className="trackings-container">
<h2 className="trackings-title">👁 Watchlist</h2>
{
charts.map(chart => (
<Collection {...chart} key={chart.symbol} />
))
}
</div>
</div>
);
}
I'm mapping the charts array above and I'm creating it below
const renderUserProjects = async() => {
const userProjects = await fetchUserProjects();
const charts = []
for(let x = 0; x < userProjects.length; x++) {
try {
const proxyURL = 'https://ixoth-tracker.herokuapp.com/';
const targetURL = 'https://api-mainnet.magiceden.dev/v2/collections/' + userProjects[x] + '/stats';
const response = await axios.get(proxyURL + targetURL);
const data = response.data
const floorPrice = data["floorPrice"];
const listedCount = data["listedCount"];
const volumeAll = data["volumeAll"];
let chartJSON = {
symbol: userProjects[x],
floorPrice: floorPrice,
listedCount: listedCount,
volumeAll: volumeAll
}
charts.push(JSON.stringify(chartJSON))
} catch(error) {
console.error(error);
}
}
console.log(charts)
return(charts);
}
I looked up on google and most of the errors caused because the element that is being mapped was not an array (usually an object). But in my case I don't think the problem is that, I tried to console.log(Array.isArray(charts)) and it printed out true Can someone help me with this problem?
function Collection(props) {
return(
<div className="chart-wrapper">
<p className="project-name">{props.symbol}</p>
<p className="floor-price">Floor Price: {props.floorPrice}</p>
<p className="listed-count">Listed Count: {props.listedCount}</p>
<p className="volume-all">Volume All: {props.volumeAll}</p>
</div>
)
}
The problem is that renderUserProjects
is async function. It returns Promise
which doesn't have map method. At the moment of rendering, it hasn't been even resolved. Moreover, each component render you start data fetching.
In this case, we have to wait until it's resolved.
function App() {
// We put [] as default value. Or we can add even a `loading` state in order to show spinner during the data fetching.
const [charts, setCharts] = useState([]);
useEffect(() => {
// On mount
renderUserProjects().then(setChart);
}, []);
return(
<div className="app-container">
or as the second option, we can transform renderUserProjects
to custom hook useUserProjectCharts
and do the same here:
const useRenderUserProjects = () => {
const [charts, setCharts] = useState([]);
const [isLoading, setIsLoading] = useState();
const [error, setError] = useState();
async function getCharts() {
setIsLoading(true);
const userProjects = await fetchUserProjects();
const charts = [];
for (let x = 0; x < userProjects.length; x++) {
const proxyURL = 'https://ixoth-tracker.herokuapp.com/';
const targetURL = 'https://api-mainnet.magiceden.dev/v2/collections/' + userProjects[x] + '/stats';
const response = await axios.get(proxyURL + targetURL);
const data = response.data;
const floorPrice = data['floorPrice'];
const listedCount = data['listedCount'];
const volumeAll = data['volumeAll'];
let chartJSON = {
symbol: userProjects[x],
floorPrice: floorPrice,
listedCount: listedCount,
volumeAll: volumeAll,
};
charts.push(JSON.stringify(chartJSON));
}
}
useEffect(() => {
getCharts()
.then(setCharts)
.catch(setError)
.finally(() => setIsLoading(false));
}, []);
return { charts, isLoading, error };
};
and use it useRenderUserProjects
as in your App component:
const charts = useRenderUserProjects();