Unable to render data in Reactjs - reactjs

I am new to react and have been debugging this from yesterday and I finally decide to post as I am clueless of what is happening.
The following react code fetches data from the api and then renders it on the UI. But, there are few strange things happening here.
I get error saying as TypeError: Cannot read property 'map' of undefined initially but when I comment out {renderTableData(data)}& save and then again uncomment & save, the data is rendering perfectly on the UI
I am thinking that before even the data gets fetched from API, it is getting passed to the function renderTableData which is why in the console undefined is printed.
Here is the code
export default function TenantList(){
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users').then((response)=>{
return response.json();
}).then((data)=>{
setData(data)
})
},[]);
function renderTableData(data) {
console.log("hello ", data)
return data.map((student, index) => {
const { name, email } = student //destructuring
return (
<tr key={name}>
<td>{name}</td>
<td>{email}</td>
</tr>
)
})
}
return (
<>
<div>
{renderTableData(data)}
</div>
</>
)
}
Please suggest a workaround

You only want to run this function if you have the data, so check for it:
{data && renderTableData(data)}

Related

How to implement error boundaries in react with MERN?

My goal is to simply dynamically present the data from a mongo database of a specific document.
const Details = () => {
const { id } = useParams()
const [product, setProduct] = useState(null)
useEffect(() => {
const fetchProduct = async () => {
const response = await fetch(`/api/products/${id}`)
const json = await response.json()
if (response.ok) {
setProduct(json)
console.log(json)
}
}
fetchProduct()
}, [id])
this code works fine as it gets the product, but my problem is occurring with the rendering:
return (
<div className="details">
<Menu />
<h1 className="movement">Product Details - {product.name}</h1>
</div>
);
}
the error that I'm getting is Uncaught TypeError: Cannot read properties of null (reading 'name') and to Consider adding an error boundary to your tree to customize error handling behavior.
my question being is how do i implement correct error handling
Just use the optional chaining operator:
product?.name
It's typical that in the first render product is not yet available so you cannot access to any of its properties. With the optional chaining operator you are covering this case.
See more: https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Operators/Optional_chaining
If you want to add Error Boundaries:
https://reactjs.org/docs/error-boundaries.html#gatsby-focus-wrapper
React renders the component before you make an api request, thus product doesn't exist (it's null based on how you set its initial value). Then when response is received you set product to state and react re-renders your component. Now product exists.
To solve it, render h1 only when product exist.
<div className="details">
<Menu />
{ product && <h1 className="movement">Product Details - {product.name}</h1> }
</div>
Also, you can render a message if product is not yet exist
<div className="details">
<Menu />
{ product && <h1 className="movement">Product Details - {product.name}</h1> }
{ !product && <p>Loading ... </p>
</div>

React, Cannot read properties of undefined Error with useEffect

I'm trying to get some weather data from an API, but I always get the same error of not being able to read properties of undefined. I've gone through different tutorials and previously asked issues, but I haven't been able to figure out what I'm doing wrong. Could anyone please give me a hand?
export default function Weather(){
const apiKey = process.env.REACT_APP_API_KEY
const weatherUrl = `http://api.weatherapi.com/v1/current.json?key=${apiKey}&q=Saxthorpe&aqi=no`
const [weatherData, setWeatherData] = useState();
const [error, setError] = useState(null);
useEffect(() => {
(
async function(){
try {
const response = await axios.get(weatherUrl);
setWeatherData(response.weatherData);
} catch (error) {
setError(error);
}
}
)();
}, [])
return (
<div className="weather-feature">
<h1>hi</h1>
<p className="location">{weatherData.location.name}</p>
<p className="temp">{weatherData.current.temp_c}</p>
<p className="weather-desc">{weatherData.current.condition.text}</p>
</div>
)
}
When pulling data like this and rendering components conditional on that data, you should account for situations in which the data is not yet available or null.
Specifically, you're attempting to render this data:
return (
<div className="weather-feature">
<h1>hi</h1>
<p className="location">{weatherData.location.name}</p>
<p className="temp">{weatherData.current.temp_c}</p>
<p className="weather-desc">{weatherData.current.condition.text}</p>
</div>
But it's not going to available on the first render (i.e. weatherData does not have a location property at first, since your default useState value is undefined).
There are many ways around this, and what you choose ultimately depends on your project and preferences.
You can use optional chaining as a simple protection against null references when checking nested properties:
return (
<div className="weather-feature">
<h1>hi</h1>
<p className="location">{weatherData.location?.name}</p>
<p className="temp">{weatherData.current?.temp_c}</p>
<p className="weather-desc">{weatherData.current?.condition?.text}</p>
</div>
Or you can return something else if weatherData is not ready. A good tool for this kind of thing is swr:
import useSWR from 'swr'
function Weather()
{
const { weatherData, error } = useSWR(weatherUrl, fetcher)
if (error) return <div>failed to load</div>
if (!weatherData) return <div>loading...</div>
return <div>hello {weatherData.location}!</div>
}
As a side note, another thing to consider is your useEffect dependencies:
useEffect(() => {
(
async function(){
try {
const response = await axios.get(weatherUrl);
setWeatherData(response.weatherData);
} catch (error) {
setError(error);
}
}
)();
}, [])
With an empty dependency array, your effect runs only on mount and unmount. If you want it to run based on some other variable(s) changing, add those variables to the dependency array.
You can debug to check the response. I think the respose is undefined from
const response = await axios.get(weatherUrl);
response = undefined => can not get weatherData property.
We are using useEffect you can debug on it by F12 in Chrome and see what happen and the reason of this bug. This is better than you come here to ask
Look: weatherData is your state, which is initially... nothing, because you don't pass any data.
So, you cannot access the location field on the first render because it does not exist yet.
It would help if you made sure weatherData exist:
return (
<div className="weather-feature">
<h1>hi</h1>
<p className="location">{weatherData?.location.name}</p>
<p className="temp">{weatherData?.current.temp_c}</p>
<p className="weather-desc">{weatherData?.current.condition.text}</p>
</div>
)

Cannot Render REST API Response in react

I am having issue with rendering the REST API response in React. I am able to see the response in console and its working there. But when I am trying to render it in UI, I am getting an error which says TypeError: Cannot read property 'State' of undefined .
I have snipped the required code and here it is.
render() {
const { getdetails } = this.state;
const itemID = 'ITAINUAT69-8982';
if (!getdetails ) {
return <div>Loading Please Wait...</div>;
}
else {
return (
<div>
{getdetails.itemID.State} // when trying to render directly, not working
// also not working in loop.
{/*
<ul>
{getdetails.itemID.map((detail, index) => (
<li key={detail.index}>
{detail.State}
</li>
))}
</ul> */}
</div>
);
}
}
}
export default Items;
Here is the response sample in Postman & console.
{
"ITAINUAT69-8982": {
"State": "Not Assigned",
"SubmitDate": "2020-09-11T04:39:51Z",
}
Thanks Everyone.
that's because in the first render getdetails is empty. you can fix this with optional chain operator:
Object.keys(getdetails)?.[0]?.State
or
getdetails?.[itemID]?.State

React Component is rendering twice

I have no idea why, the first render shows an empty object and the second shows my data:
function RecipeList(props) {
return (
<div>
{console.log(props.recipes)}
{/*{props.recipes.hits.map(r => (*/}
{/* <Recipe initial="lb" title={r.recipe.label} date={'1 Hour Ago'}/>*/}
</div>
)
}
const RECIPES_URL = 'http://cors-anywhere.herokuapp.com/http://test-es.edamam.com/search?i?app_id=426&q=chicken&to=10'
export default function App() {
const classes = useStyles();
const [data, setData] = useState({});
useEffect(() => {
axios.get(RECIPES_URL)
.then(res => {
setData(res.data);
})
.catch(err => {
console.log(err)
})
}, []);
return (
<div className={classes.root}>
<NavBar/>
<RecipeList recipes={data}/>
<Footer/>
</div>
);
}
I don't know why and I have struggled here for over an hour (React newbie), so I must be missing something.
This is the expected behavior. The reason you see two console logs is because, the first time RecipeList is called with no data (empty object), and the second time when the data becomes available. If you would like to render it only when the data is available you could do something like {Object.keys(data).length > 0 && <RecipeList recipes={data}/>}. By the way this is called conditional rendering.
This is perfectly normal, React will render your component first with no data. Then when your axios.get returns and update data, it will be rendered again with the new data

How to use getquery with amplify <Connect/> component in React

I have been trying to use the together with a getquery in react but I can't get it to work. Below is the code I put together
const input = {
id: this.props.Id
};
return (
<div>
<Connect
query={graphqlOperation(getRecords, input)}
subscription={graphqlOperation(onCreateRecords)}
onSubscriptionMsg={onNewRecord}
>
{({data, loading, error}) => {
if (loading) return "Loading"
if (error) return "Error"
const ListRecord = data.getRecords
console.log('ListRecord', ListRecord)
//console.log returns undefined
return <div>...
</div>
}}
</Connect>
</div>
Deos anyone know what I'm doing wrong? Thanks!
It's hard to say based on what you've posted alone. Is there any additional information in the 'data' object?
Also, Have you tried doing:
query={graphqlOperation(getRecords, {input})}

Resources