Is it possible to force a ListView to re-render, even if the data in the dataSource has not changed? I have a ListView within a tab bar in my app and I want it to redraw eve
This is probably a bit overkill but I'm just replacing the datasource on componentDidUpdate (maybe this is bad for performance? I dunno haha)
componentWillMount() {
this.ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
});
this.dataSource = this.ds.cloneWithRows(this.props.shiftsList);
}
componentDidUpdate() {
this.ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
});
this.dataSource = this.ds.cloneWithRows(this.props.shiftsList);
}
I know I'm a bit late but I'm sure that this is still relevant. There's an even easier approach to this... The first example provided by Jason is by all means a good solution but I'm thinking of those whom easily gets confused. If so, use this.
// On component initalization
componentWillMount() {
this.UpdateData();
}
// When the component updates
componentDidUpdate() {
if (this.state.data != this.props.data)
this.UpdateData();
}
// Function to update the ListView component data
UpdateData() {
var source = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
this.setState({
data: this.props.data,
dataSource: source.cloneWithRows(this.props.data)
});
}
I also recommend to implement Redux in your application. That way you could store the new, updated array value in a reducer and then store it locally in a state and later use an if statement in the componentDidUpdate function to determine whether the data is updated or not.
The React debugger logs no performance based complaints or warnings whatsoever...
So your use-case, as I understand it, is to re-render all rows of ListView because of value
changes. I don't know what value
is, up to you to determine it, but I will use value
to explain my answer:
There are a few ways to solve this. each have pros and cons:
<ListView key={value} ... />
!! It tells React that ListView needs to get re-render when value changes (it will be unmounted, remounted).this.setState({
dataSource: new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !==
r2 }).cloneWithData(this.props.data)
});
value
and implements rowHasChanged properly. For instance: (r1, r2) => r1.value !== r2.value && r1.data !== r2.data
(<- this is JUST a possible way to represent the data, you have to chose your format, I just assumed you did clone dataSource with nextProps.data.map(data => ({ data, value })
).to me, the third and last solution is the best because:
value
s)here is an other answer I gave on that subject:
What are the exact inputs to rowHasChanged in ListView.DataSource
The best way to "update" this would be to clone the data item in question rather than doing a flag hack as the r1 !== r2
is already hinting at. Instead of updating an individual item, change the "pointer" itself by cloning.
For this particular issue update the item in the array like so.
arr[i] = { ...arr[i], someKey: newValue }
This will replace the "someKey" property with "newValue" and the current row will have a new pointer.
Here is a good resource to learn about immutability in modern JavaScript that react native uses: https://wecodetheweb.com/2016/02/12/immutable-javascript-using-es6-and-beyond/
You can call this.forceUpdate() to force a re-render.
You can do this in a simple onClick
handler that you attach to the tab.
More info here, on the official docs
However, if there are other rules dictating if there should be an update or not, you can try replacing the dataSource
altogether with a new one, making it have a new reference. That will also make it update.
Something along the lines of
this.setState({ data : newDataSource… });