React object.map not updating due to the key - javascript

The basic problem I'm having is that I'm updating my data using an AJAX request and then setting the state of data, but in the view, the data never update even though my state is updated. I've figured out that it's because the key is the same (which it should be because I'm just using the ID mongoose provides).
If I do things like set the state to nothing and then set then set the new data then it updates. Or if I set the key to a randomly generated key it also works, but both of these don't feel right. I want to know what the correct way to re-render an updated object when using the map function.
It looks something like this:
Object.keys(this.state.data).map((i) => (
<MyComponent key={ this.state.data[i]._id }
))
And then I have a basic AJAX request that does this.setState({ data: response.data }).
How do I make react update the data in the view for the updated item properly?

Can you add the index as a prefix to the _id?
key={ `${i}_${this.state.data[i]._id}`}

I am not really sure it is related to the key, if you console.log(this.state.data) just before your code it gets updated when it should? it seems to me that the props are not getting passed to the component.
I mean I often use the index of map in the key in the lists I never had any problem with that.

Related

Update the cache and trigger a re-render in Apollo

I'm trying to update the cache of a certain item but changes aren't being reflected on to the ui , I have an item which is being fetched by a query that has a lot of variables and I have no access to them on the component that I'm updating that Item on and that Item is also part of a paginated list , so my code was
update = (cache)=>{
cache.data.data['ItemType_'+itemId].title = "New title"
}
as far as I know this code should update the cache of that item but it doesn't show it in the ui , is there a way to update a single item in the cache and have the result rendered ?
Directly updating the cache doesn't cause a re-render afaik. I recommend running a query with fetchPolicy: "cache-only" after you update the cache. That will update the component's data and cause a re-render without hitting the network.
Try and also make sure you are returning the correct data from the mutation.
Return the correct fields from the mutation. The required field can be id. If it is not returned from the mutation, then there will be no refresh or re-render.

Redux container cannot display the reducer handling an API call

I have been building a basic weather app using React, Redux, Redux-promise and Axios (handling an API for the current weather using openweathermap.org).
If the button gets clicked, the weather parameters of the city (Cecciola) should be displayed on the console.
The Action correctly retrieves the data and, thanks to Promise, it is passed onto the reducer as a normal payload.data, not a promise.
Then, the container responsible for the rendering of the city.name is connected to the reducer managing the weather (so that you can access it using this.props) but, if the button is clicked, the console.log(this.props.tempo....) says that the object is undefined. Why?
GitHub Repo link
Trying your repo, logging to the console this.props.tempo works just fine for me in the render method of ceciola component.
Where I see the error, is in your renderR() function. You're attempting to use diocane.city.name but there is no 'city' property for that object.
Try: <p>{diocane.name}</p> to get the name.
_______ UPDATE ________
Response to your comment: I pulled the latest version from the repo, and again, everything seems to work just fine when you click the button to retrieve the data. As the code is now, you are doing:
console.log(this.props.tempo[0])
So, on first load of the component, you have nothing in the props.tempo array, so you see undefined in the console. When you click the button, you now have a single object in the array and that log statement works just fine.
I changed your render() method to:
render() {
if (this.props.tempo.length > 0) {
console.log("TEMPO", this.props.tempo[0])
console.log("ID", this.props.tempo[0].id)
}
return (
<div>
{this.props.tempo.map(t => {
return <div key={t.id}>{t.name}: {t.main.temp} </div>
})}
</div>
);
}
And it logs out the expected information. You just need to confirm that the tempo prop has something in the array before attempting to access it. And then, when you do, make sure you're accessing the individual object(s) inside. I show an example of this in the return() method above: using map to iterate and return a new array of <div> elements with the tempo object info.

Sharing a State Array

Have kinda a unique question, in my code I have a listener to a database that loads down objects into an array.
All I do when I load it in is
AddObject(obj){
this.setState({
Data: [...this.state.Data, obj]
});
}
Pretty simple. However this listener function, there is no exact time when need data will be added. When I go to use that Data sent in Data, I went to pull it out of the Data Array, however I am worried if I try copying data out of the array, or removing the "seen" data, I will get weird behaivor if my listener function triggers and I try adding data to the array at the same time.
Is there some sort of a way to do this? I guess you could call this a shared resource
Ideally, I would have something like this:
loadDataIN(){
var LengthToGrab = this.state.Data.length;
//we need to remove this length, now any new data will be added to index 0
}
Does this make sense? basically I am trying to figure out the best way to remove data from this array, and not have to worry about overwritting, or losing data. Maybe some sort of processing que
From official doc
setState() enqueues changes to the component state and tells React
that this component and its children need to be re-rendered with the
updated state.
You don't need to worry that two kinds of situation would have conflict in the same time.
setState() enqueues the pending state before the changes be rendered.
In fact, no matter how mechanism be implemented, React is a framework of JavaScript which is working on a model event-loop.
So if you want to pull out the data from this.state.Data:
loadDataIN(){
this.setState(function(prevState, props) {
// this.fetchData = prevState.Data;
return {
Data: []
};
});
}

React Native - populating ListView with async data

I'm getting a list of items as a prop through the redux store. This prop is asyncronous.
My ListView works with syncronous hardcoded data. So the problem is populating with the prop when I actually receive it.
I'm making a ListView out of this item prop data. What's the best practice on life cycle choices to setState with this prop? I've tried componentDidMount - but that's too early and only called once. I tried componentWillReceiveProps - I get the prop, but my view doesn't change. I also tried componentWillUpdate and I get too many calls! I'm tempted to put it in the render function because I know I can grab that prop when I get it but that makes the render function no longer pure.
Thanks for any help!
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.props.items);
})
The solution was that I actually needed to convert items as a List from immutable to a JS Array for the ListView. Not what I originally thought the problem was in the question.
Here's the solution:
componentWillReceiveProps(newProps){
if(newProps.items){
this.setState({
dataSource: this.state.dataSource.cloneWithRows(newProps.items.toJS())
})
}
}
I'm still wondering if I'm using best practice by using componentWillReceiveProps. I'm also wondering if it's a little strange that I have to convert from a List to an Array, but if it's purely presentational that is ok, right?
When using componentsWillReceiveProps, it's good practice to check whether those props have changed. Also not sure why you have to do .toJS(), you just need to return a new array so React knows to update.
componentWillReceiveProps(newProps){
if (newProps.reasonOptions !== this.props.reasonOptions){
this.setState({
dataSource: this.state.dataSource.cloneWithRows([...newProps.items])
});
}
}

Dynamic defaultValue on Combobox React Widgets

I'm fairly new to javascript and I'm currently making a web client that display some data a database. Pretty standard stuff I guess. I use react.js and I installed react-widgets to get some nice widgets. The comboxbox I use is getting it's data from a mongo database depending on the collection chosen from another comboxbox. So by changing the collection, the data inside is updated to reflect the change. This works well, but I can't seem to be able to set the default value. Here the code to render the comboxbox:
<Combobox onChange= {this.handleOnChange} data = {this.state.myValues} defaultValue= {this.state.myValues[0]}/>
I have had this issue with a couple of widgets that does not seem to be able to get updated dynamically. They work if all the data is there the first time I'm rendering (static data for example), but they don't if the data is empty at first and gets populated afterward. *I did make sure I call setState to call the render function.
Did I miss something? Is it a javascript issue that I don't understand?
Thanks!
Try wrapping the Combobox with a condition.
Something like this
{ this.state.myValues[0] &&
YOUR_TAG_COMBO
<Combobox onChange= {this.handleOnChange} data = {this.state.myValues} defaultValue= {this.state.myValues[0]}/>
}
I think you might be better off using the value prop, instead of defaultValue, it will give you more control over the component, and it will repopulate the form element when the state has changed.

Categories