I am trying to create a simple table using the data i recieve from the backend from an API call using Ant design in React. I am using Ant design version :
"antd": "^5.1.1",
I am making a simple api call to my backend and storing the result in a state, then tring to use the state itself or using another function to make the api call by itself, and store the value if i get a response, or just return an empty array. I am not able to figure what possibly is throwing the error:
Uncaught TypeError: rawData.some is not a function
at Table.js:89:1
at mountMemo (react-dom.development.js:15442:1)
const getTableData = useCallback(async () => {
const data = (await retrieveGRNASN(GRNid) ?? []);
console.log('data', data);
return data;
},);
....
// this is my table call
<Table dataSource={getTableData()}
columns={columns}
size="small"
pagination={false} />
I searched multiple solutions on stackoverflow for similar problems but nothing is helping me. I am not even sure if i am getting closer also as the whole page crashes with the same error.
getTableData() will return a promise, but the prop dataSource expects it to be an array.
So promise does not have the some method.
Instead of that you should have a state of the TableData and when the promise is resolved it should be updated with the data.
import { useState, useEffect } from "react";
export default function App() {
const [tableData, setTableData] = useState([]);
useEffect(() => {
const getTableData = async () => {
const data = await retrieveGRNASN(GRNid);
if (data) setTableData(data);
};
getTableData();
}, []);
return (
<div className="App">
<Table
dataSource={tableData}
columns={columns}
size="small"
pagination={false}
/>
</div>
);
}
Related
I have a react component that gets data from an API end point. For the purposes of debugging when I call the API I log the result of the API call to the console and it looks like this:
The problem I have is that when I try to render the BreadCrumbLinks Property in my component I get this error:
TypeError: Cannot read properties of undefined (reading 'map')
at BreadCrumbHeader
I am getting an "Undefined" error, but I know that the data is present because I can read and render all of the other fields (for example BreadCrumbBgImage).
Also, if I comment out the map/loop the rest of the data is displayed correctly when the page loads. Then if I uncomment it out and save the file the data for the map/loop now shows correctly.
I can only assume that the code is trying to render the contents of the loop before it has been loaded.
This is what the code for the component looks like:
import React, { useState, useEffect } from 'react';
import API from "../../API";
import { useLocation } from 'react-router-dom';
import { BreadCrumbTitleSection, SubtitleSection, Subtitle } from './breadCrumbHeaderStyle';
import { Breadcrumb } from 'react-bootstrap';
function BreadCrumbHeader() {
const location = useLocation();
const [breadCrumbData, setBreadCrumbData] = useState([]);
const getBreadCrumbData = async () => {
const breadCrumbHeaderResponse = await API.fetchBreadCrumbHeader(location.pathname);
setBreadCrumbData(breadCrumbHeaderResponse);
console.log("OUT-PUT-OF-API-CALL");
console.log(breadCrumbHeaderResponse);
console.log("END-OF-OUT");
};
useEffect(() => {
getBreadCrumbData();
}, [location.pathname]);
return (
<div>
<BreadCrumbTitleSection backgroundUrl={breadCrumbData.BreadCrumbBgImage}>
<div className="container">
<div className="row no-gutters">
<div className="col-xs-12 col-xl-preffix-1 col-xl-11">
<h1 className="h3 text-white">{breadCrumbData.BreadCrumbTitle}</h1>
<Breadcrumb>
{breadCrumbData.BreadCrumbLinks.map(breadCrumbLink => (
<Breadcrumb.Item href={breadCrumbLink.LinkUrl} key={breadCrumbLink.Id} active={breadCrumbLink.IsActive}>
{breadCrumbLink.LinkText}
</Breadcrumb.Item>
))}
</Breadcrumb>
</div>
</div>
</div>
</BreadCrumbTitleSection>
<SubtitleSection>
<Subtitle> {breadCrumbData.SubTitle}</Subtitle>
</SubtitleSection>
</div>
);
}
export default BreadCrumbHeader;
Can anyone explain what is going on here and how I can solve i?
You are trying to map data before its fetched, so its an empty array (initial value of breadCrumbData state). You should use optional chaining:
{breadCrumbData?.BreadCrumbLinks?.map(breadCrumbLink =>
You are tryng to map your array before the state change, the useEffect is called on first render, your array don't have the state in the first render, you can use something like a loading hook, like this
const [loading, setLoading] = useState(false)
useEffect(() =>{
setLoading(true)
fetchData()
},[])
const fetchData = () =>{
//my api call
setLoading(false)
}
return (
{loading ? (
// my loading message or function
): (
// my show component
)}
)
this is a just an litle example how you can do
import { useEffect, useState } from "react";
function Popular() {
const [popular, setPopular] = useState([]);
useEffect(() => {
getPopular();
}, []);
const getPopular = async () => {
const api = await fetch(
`https://api.spoonacular.com/recipes/random?apiKey=${process.env.REACT_APP_RECIPE_API_KEY}&number=9`
);
const data = await api.json();
setPopular(data.recipes);
};
return (
<div>
{popular.map((recipe) => {
return (
<div>
<p>{recipe.title}</p>
</div>
);
})}
</div>
);
}
export default Popular;
I am pretty new to React, and I encountered this issue which I have been trying to fix to no avail. The code is a component that is to return a list of recipe title to my app. I am fetching data from an API in the getPopular() function which is set to the setPopular function variable of the useState() method. But when I save my work and return to the browser, the changes does not display. The list does not display, but if I console.log(data.recipes) it displays on the console.
Before now, if I made any change (maybe a text change) the React app renders it without reloading, but now I have to reload the page before I see the change.
Please how do I fix this issue? So that I can see changes without having to reload the page manually.
Not saying that this is the problem, but getPopular() should not be called after its declaration? By this I mean:
const getPopular = async () => {
const api = await fetch(
/...
};
useEffect(() => {
getPopular();
}, []);
Another thing that bugs me is, although JS/React is case sensitive, I really think you should avoid having a const called popular, since your functions is Popular.
Please, let me know if the order did matter for your problem. I will review some react classes soon, if i get another inside, i'll let you know.
import React from 'react';
const url = 'https://randomuser.me/api/?results=10'
async function List() {
const data = await fetch (url)
const response = await data.json()
return (
<div>
{response.map((item)=>(
<div>{item.results[1].name.first}</div>
))}
</div>
)
}
It also throws this: The above error occurred in the component:
at List
at div
at App
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
If you working with a functional component. You need to use React hooks for API calls. You can use useEffect hooks to call the API.
Example:
const { useState } = React;
function useFetchData() {
const [data, setData] = React.useState([]);
React.useEffect(() => {
return fetch("https://randomuser.me/api/?results=10")
.then((response) => response.json())
.then((responseJson) => {
setData(responseJson.results);
})
.catch((error) => {
console.error(error);
});
}, []);
return { data };
}
function App() {
const { data } = useFetchData();
return (
<div id="quote-box">
{data.map((item) => (
<div>{item.name.first}</div>
))}
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('react')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Calling an API inside a component is a side effect and React doesn't want that. React components expect you to provide the data and render that data immediately. If you want to call an API before rendering the component, use a side effect method like useEffect() and call that API inside the lambda. The component now knows that there is an expected side effect and will re-render once the data has updated.
This is my component.
const DashboardContext = React.createContext()
function DashboardStateProvider({ children }) {
const Provider = DashboardContext.Provider
return (
<WithSubscription Provider={Provider} connectedAccount={wallet.account}>
{children}
</WithSubscription>
)
}
async function WithSubscription({ Provider, connectedAccount, children }) {
const { data } = await asyncCallHere()
return ( <Provider value={{ treasury }}> {children} </Provider> )
}
function useDashboardState() {
return useContext(DashboardContext)
}
export { DashboardStateProvider, useDashboardState }
In the code, one can see asyncCallHere. Before this code, asyncCallHere was synchronous which means I had no mistake in the code. But I need it to make async, so I had to add async to withSubscription function. Hope the code makes sense.
The problem is that because I put await and async there, it results in the following error:
Unhandled Rejection (Error): Invalid hook call. Hooks can only be
called inside of the body of a function component. This could happen
for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app See facebook dev page for tips about how to debug and
fix this problem.
I'd appreciate the quick answer to fix this, due to the fact that I am not react developer and I don't intend to understand what's happening there in deep other than to fix it.
Hooks cannot be async.
You always need to return sync data from the hook.
However, if you want to do some async operation inside the hook, you can do it inside useEffect to store the data in the hook state and return that data from the hook itself.
import React, {useEffect, useState} from 'react'
function useAsyncCallHere() {
const [data, setData] = useState(null)
useEffect(() => {
async function getData() {
const response = await asyncCallHere()
setData(response.data)
}
getData()
}, [])
return data
}
function WithSubscription({ Provider, connectedAccount, children }) {
const data = useAsyncCallHere()
return ( <Provider value={{ data }}> {children} </Provider> )
}
I'm confused about how to use localStorage to persist the data that's coming from calling the API.
I want whenever I refresh the page, the callApi inside useEffect to not render new data and keep the existing data unchanged.
Any help would be appreciated.
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { Layout, Loading, OverviewHeader, OverviewSubHeader, SiteCard } from '../components';
const Overview = () => {
const [loading, setLoading] = useState(true);
const [sites, setSites] = useState([]);
useEffect(() => {
async function callApi() {
const response = await axios.get(`https://randomuser.me/api/?results=3`);
const sites = response?.data?.results;
console.log('sites', sites);
setSites(sites);
await localStorage.setItem('sites', JSON.stringify(sites));
setLoading(false);
}
callApi();
}, []);
return (
<div>
<Layout>
<OverviewHeader />
<OverviewSubHeader />
<div className='overview-page-wrapper'>
{loading ? (
<Loading />
) : (
sites.map(site => {
return (
<React.Fragment>
<SiteCard
key={site.login.uuid}
siteId={site.login.uuid}
image={site.picture.large}
firstName={site.name.first}
lastName={site.name.last}
city={site.location.city}
country={site.location.country}
sensors={site.dob.age}
notifications={site.registered.age}
latitude={site.location.coordinates.latitude}
longitude={site.location.coordinates.longitude}
{...site}
/>
</React.Fragment>
);
})
)}
</div>
</Layout>
</div>
);
};
export default Overview;
I'm not too sure what you're trying to accomplish, seeing as you'd likely want to refresh that data at some point.
Maybe you could indicate what behaviour/scenario you're trying to cater for?
In any case, to answer your question, what you could do is smth like:
const [displayedSites, setDisplayedSites] = useState([])
// this does both setting the state for your UI
// and stores to localStorage
const setAndSaveDisplayedSites = (fetchedSites) => {
setDisplayedSites(sites)
localStorage.setItem('sites', JSON.stringify(sites))
}
useEffect(() => {
(async function () {
const localSites = localStorage.getItem(sites);
if (!localSites) {
// this will only ever fetch if it is your first time mounting this component
// I suppose you would need to call setAndSaveDisplayedSites
// from a "refresh" button
const fetchedSites = await getSitesFromAPI()
setAndSaveDisplayedSites(fetchedSites)
return
}
const parsedLocalSites = JSON.parse(localSites)
setDisplayedSites(parsedLocalSites)
})()
}, [])
also checkout this hook that takes care of some things for you: https://usehooks.com/useLocalStorage/
Use the useContext hook for this purpose OR if you really just want to use the local storage anyhow, then use it but manage different states/variables for that.
Your current state (that you want to render on the screen)
Your fetched data (the one that you want to keep)
Hope this makes sense. Thankyou!