Probably it's a newbie question... I get a json response with an object from a fetch() running into a function on componentDidMount(). The result is saved into a state
data:
{
id: 1,
name: 'joseph',
tickets:
[
{id: 334, descripton: 'example1'},
{id: 768, descripton: 'example2'},
],
}
I need to list this array "tickets" in render ().
componentDidMount(){
this.getFetch(...);
}
showTickets(WTickets){
console.log(WTickets);
WTickets.map((item)=>{
return (item.id)
})
}
render(){
return(
<View>
{this.showTickets(this.state.data.tickets)}
</View>
)
}
But the "first return" is "undefined", generating error and then the state changes to the correct result. The fetch is running with async await, but still show the "undefined" first.
The console.log show 2 results: one "undefined" and another with the result.
Any good soul to help me, please?
It's because at the start this.state.data.tickets is undefined and you are calling it in the render function which is not gonna wait until this.getFetch() finishes. So.. you can do a conditional rendering to check if this.state.data.tickets exist in rendering
replace {this.showTickets(this.state.data.tickets)}
with {this.state.data!==undefined? this.showTickets(this.state.data.tickets) : null}
What we are doing here is first checking if this.state.data.tickets is not undefined. While it is undefined (at the start) we return null, when it stops being undefined we call this.showTickets.
You can even initialize this.state.data as an empty array, and you can delete the part when we check if it's undefined since an empty array will return false
constructor() {
super();
this.state = {
data: []
};
}
....
....
//in render function
{this.state.data? this.showTickets(this.state.data.tickets) : null}
...
Related
I'm trying to fetch some data from an API. The below code "works" when I log the results to console like console.log(liveInfo.tracks), but when I try to do console.log(liveInfo.tracks.current) it fails with this error: TypeError: Cannot read properties of undefined (reading 'current'). Isn't liveInfo.tracks.current how one would normally access the key-value pair?
componentDidMount() {
fetch('https://kchungradio.airtime.pro/api/live-info-v2')
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
liveInfo: result
})
}
)
}
The json looks more or less like this:
{
"station": {
"env": "production",
},
"tracks": {
"previous": {
"name": "a",
"metadata": {
"id": 1,
},
},
"current": {
"name": "b",
"metadata": {
"id": 2,
}
}
}
}
Because at some point liveInfo.tracks was undefined
Although there is a lack of hints, a common mistake when fetching data from lifecycle is trying to retrieve the value through the state before setData occurs.
Before you use liveInfo, make sure that data fetching is finished
like this
class SomeComponent = {
render() {
if(!this.state.liveInfo?.tracks?.current) return null
....
}
}
It looks you are trying to access to the current before it is filled on the componentDidMount, it means before the fetch has been performed. I suggest you to initialize the state like this:
state = {
isLoaded: false,
liveInfo: {
tracks: {
curent: {}
}
}
};
So you will be able to access the current property inside tracks without facing the TypeError. I made a codesandbox, so you can check an example there.
If this does not solve your problem, please let me know ;)
Your call looks right,
another way to get the value is console.log(liveInfo.tracks["current"]);
but I think your tracks has no value at runtime. Maybe you can show us more code where you are call console.log.
Maybe you run twice in your statement and at first time it is undefined and throw the error. So add a null check like this console.log(liveInfo?.tracks?.current);
Use Question mark (?)
? will check for null. If your object is null ? will handle it.
liveInfo?.tracks?.current
this is the right approach.
Further -
liveInfo?.tracks?.current?.metadata
I have arrays:
sportmen (like this: [{id: 1, surname: 'Williams', typeSport: 5}, ...])
sports (like this: [{id: 4, name: 'football'}, ...])
I using map function to send every sportsman from Main component to ListRow component:
{this.props.sportsmen.map(item => {
return (<ListRow key={item.id} directory={item}/>);
})}
In ListRow component I print all data about every sportsman, but id value typeSport I changing to sport name. My realization is working, but I have an error in console.
showSport() {
const tmpSport = this.props.sports.find(item => item.id === this.props.directory.typeSport);
return tmpSport.name; // error is here!
}
render() {
return (
<div>
<div>{this.props.directory.surname}</div>
<div>{this.showSport()}</div>
</div>
);
}
Error:
Uncaught (in promise) TypeError: Cannot read property
'name' of undefined
Why I get this error and how can I remove errors?
the sports array doesn't contain a sport whose id matches this.props.directory.typeSport. one solution would be to modify what is returned to handle cases where the sport doesn't exist.
return tmpSport ? tmpSort.name : 'not found'
or something like that
I declare state via redux connect
const mapStateToProps = state => ({
singleBase: state.interaction.base
});
export default requiresLogin()(connect(mapStateToProps)(BasePage));
The state shows fine via console log console.log(this.props.singleBase);
id: "5b757e6743904228586a5a7f"
creatorId: "5b6e39ce08406602d0a9e125"
title: "tester"
currentUsers: 2
messages: 0
On the backend I have the following model:
const BaseSchema = mongoose.Schema({
creatorId: { type: mongoose.Schema.Types.ObjectId, required: true },
title: { type: String, required: true },
currentUsers: { type: Number, default: 0 },
messages: { type: Number, default: 0 }
});
But when I try to console log the value of currentUsers: console.log(this.props.singleBase.currentUsers); I get the following error: Cannot read property 'currentUsers' of undefined.
I tried both setting the Schema to a pure number, e.g. 5, as well as as a text "5". Neither one works. What detail am I missing to be able to get the value of currentUsers ?
EDIT & SOLUTION:
const users =
this.props.singleBase && this.props.singleBase.currentUsers !== undefined
? this.props.singleBase.currentUsers
: 0;
return (
<div>
<h2>{users}</h2>
</div>
);
Here we ensure that this.props.singleBase exists and is true, while I make sure that this.props.singleBase.currentUsers has a value that is not undefined. If both evaluates true I display this.props.singleBase.currentUsers. The point of this is that until the asynchronous action has completed the singleBase will be empty. Once filled with data, I can display the currentUsers value.
You are most probably getting this data asynchronously, this is why you are getting this error. Before logging this.props.singleBase you should see an undefined in the console. This does not fire an error but if you try to get some property of an undefined object you hit this error. Trying to log undefined objects is ok, but trying to log a property where this object is undefined is not since at this time that object is undefined.
You can put a condition before your log:
this.props.singleBase && console.log(this.props.singleBase.currentUsers);
This is what will you do to render your items in the future instead of logging them. So, always remember, if you are doing an asynchronous job, there will be no data in the first render.
const users =
this.props.singleBase && this.props.singleBase.currentUsers !== undefined
? this.props.singleBase.currentUsers
: 0;
return (
<div>
<h2>{users}</h2>
</div>
);
Here we ensure that this.props.singleBase exists and is true, while I make sure that this.props.singleBase.currentUsers has a value that is not undefined. If both evaluates true I display this.props.singleBase.currentUsers. The point of this is that until the asynchronous action has completed the singleBase will be empty. Once filled with data, I can display the currentUsers value.
It might be happening because you're trying to console.log it before the current state is loaded. Try setting some flag like loading=true while you're getting your asynchronous data, and then change it to false after loading it.
I have a simple React project that in short is like a little restaurant. And the restaurant can only serve certain dishes when all ingredients are available.
So I wrote something to check for each dish that all ingredients are available / true. But within my JSX I am getting the following error TypeError: Cannot read property 'status' of undefined (screenshot provided).
However where you can see I have a console.log at // 1., the status property is defined.
Link to my public repo: https://github.com/danny-faith/dynamenu/tree/update/ingre-object
Use update/ingre-object branch
Ingredients object
const ingredients = {
egg: {
status: true
},
beef: {
status: false
}
}
Menu object
const food = {
item1: {
name: "Spaghetti Carbonara",
desc: "With egg yolk and guanciale",
price: 1724,
ingredients: ['spaghetti','egg','pancetta'],
status: "available"
}, ...
}
Code insinde JSX
{
Object.keys(this.state.menu).map(key => {
console.log(this.state.ingredients['egg'].status); // 1.
if (menu[key].ingredients.some(val => this.state.ingredients[val].status === true) ){
return <MenuItem key={key} data={menu[key]} />
}
})
}
I dont see where you set your state , but this error can simply be avoided by adding checks state.ingredients like below.
if (menu[key].ingredients
.every(val => {
return this.state.ingredients[val] ?
this.state.ingredients[val].status === true :
false;
})){
return <MenuItem key={key} data={menu[key]} />
}
A better practice would be to take the if condition to a separate function.
EDIT, added extra closing parenthesis to complete .some() function.
Since you are mapping an object maybe the problem is not on the specific ingredient that you log.
I think Cannot read property 'status' of undefined referred to this.state.ingredients[val].status depends on a val that is not defined on your ingredients object nested in one of the menu properties.
You probably have a menu ingredient that is not present in the ingredients.
[EDIT]
Looking at your repo I see:
item1: {
name: "Spaghetti Carbonara",
desc:
"With egg yolk and guanciale",
price: 1724,
ingredients: ['egg','spaghetti','pancetta'],
status: "available"
},
...
And your ingredients are:
const ingredients = {
egg: {
status: true
},
beef: {
status: false
}
}
So, for instance, ingredients['spaghetti'] or ingredients['pancetta'] are undefined.
I have an API call which is returning data and the best I can see I am returning the options in the correct way but for some reason I can't get React Select to show the options. Is there something that I am missing?
searchGroups(searchString){
if(!searchString) return Promise.resolve({ options: [] });
UserGroups.getUserGroups(searchString).then((res) => {
let groups = [];
groups = res.groups.map((d) => ({
value: d.group_ID,
label: d.group_name
}))
return {options: groups};
}, (e) => {
this.setState({
searchError: e.message
})
})
}
From what I can see the groups array is (upon a search) returning as
[
{value: 1, label: "Admins"}
{value: 22, label: "Asset Group"}
{value: 2, label: "Read-only"}
]
However the search box is being suspended with a "loading..." message and the load spinner stays. I can see the API has returned but no options are being displayed.
This is how I implement the Select is there an option I am missing? I have tried both valueKey and labelKey but neither have worked for me either.
<Select.Async
multi={true}
onChange={this.onChange}
loadOptions={this.searchGroups}
value={this.state.value}
/>
I'm sure it is how I'm returning the data but not sure where this is going wrong and what formatting I need to correct. Any help would be greatly appreciated.
The problem was a missing return before UserGroups.getUserGroups(... This caused the async code to get executed and show up in the network log, but the results wouldn't reach Select.Async. It would be nice if react-select would give an error if calling loadOptions returns undefined, but in that case it assumes a callback will be used to provide the result.