I'm trying to display a checkbox alongside each row in the list. Upon clicking on the checkbox, I want it to -be selected/de-selected. I do this by updating the array element property. However, the row is not updated until I scroll far away and then scroll back. I also tried the extendedState prop but that did not help too.
checkboxSelected(item) {
item.selected = !item.selected
}
<Checkbox checked={!!item.selected} onPress={this.checkboxSelected.bind(this, item)} />
Any help would be much appreciated. Thanks
Shouldn't you be using setState or dispatching an action instead of mutating the object?
item.selected = !item.selected
Same problem.. ..still searching for solution..
I did try mutating the state but it did not help.
constructor(props) {
super(props);
let { width } = Dimensions.get('window');
this._dataProvider = new DataProvider((r1, r2) => {
return r1 !== r2;
});
this._layoutProvider = new LayoutProvider(
index => {
return index;
},
(type, dim) => {
dim.width = 400;
dim.height = 100;
}
);
this._rowRenderer = this._rowRenderer.bind(this);
this.state = {
list,
dataProvider: this._dataProvider.cloneWithRows(list)
};
}
//Given type and data return the view component
_rowRenderer(type, item) {
return (
<View>
<CardItem>
<Left>
<Body
style={{
height: 100,
justifyContent: 'center'
}}
>
<Text>{item.name}</Text>
</Body>
</Left>
<Right>{this.renderCheckbox(item)}</Right>
</CardItem>
</View>
);
}
render() {
return (
<RecyclerListView
layoutProvider={this._layoutProvider}
dataProvider={this.state.dataProvider.cloneWithRows(this.state.list)}
rowRenderer={this._rowRenderer}
extendedState={this.state.selectedJson}
/>
);
}
checkboxSelect(item) {
let list = this.state.list;
_.map(list, listItem => {
if (listItem.name === item.name) {
listItem.selected = !listItem.selected
}
return listItem;
});
this.setState(prevState => {
return {
list,
dataProvider: prevState.dataProvider.cloneWithRows(list)
};
});
}
Your rowHasChanged implementation will return false here. You should maintain list of selections in extended state and let the component consume it.
Can you please explain how rowHasChanged function works? Do the r1, r2 parameters correspond to previous and current values of row? If that's the case, changing the changing the selected property should cause it to return 'true`.
I also tried maintaining the list of selected items in a separate object and pass it to the extendedState props. However that didn't work too. The checkbox is only selected after scrolling away and back. So I think the rowHasChanged function is working fine but it's being evaluated only after the scrolling.
_rowRenderer(type, item) {
return (
<View>
<CardItem>
<Left>
<Body
style={{
height: 100,
justifyContent: 'center'
}}
>
<Text>{item.name}</Text>
</Body>
</Left>
<Right>
<CheckBox
checked={!!this.state.selectedJson[item.slug]}
onPress={this.checkboxSelect.bind(this, item)}
/>
</Right>
</CardItem>
</View>
);
}
render() {
return (
<RecyclerListView
layoutProvider={this._layoutProvider}
dataProvider={this.state.dataProvider.cloneWithRows(this.state.list)}
rowRenderer={this._rowRenderer}
extendedState={this.state.selectedJson}
/>
);
}
checkboxSelect(item) {
let list = this.state.list;
_.map(list, listItem => {
if (listItem.name === item.name) {
listItem.selected = !listItem.selected
}
return listItem;
});
let selectedJson = this.state.selectedJson;
selectedJson[item.name] = !selectedJson[item.name];
this.setState(prevState => {
return {
list,
selectedJson,
dataProvider: prevState.dataProvider.cloneWithRows(list)
};
});
}
@sksin28 The problem is, you're mutating the object directly, instead of making a new object. That means that the reference is the same
listItem.selected = !listItem.selected
And when the rowHasChanges runs, it won't see that there are any changes.
const row1 = {
label: 'First Row',
selected: false
}
// This is where the issue is
row1.selected = true;
Instead, you should be making a new object
const row 2 = {
...row,
selected: true
}
So, in your code:
this.setState(prevState => {
return {
list: _.map(prevState.list, listItem => {
if (listItem.name === item.name) {
// Here, you should return a new object.
return {
...listItem,
listItem.selected = !listItem.selected
};
}
return listItem;
})
};
});
Thanks @AbdallaMohamed @naqvitalha . It worked. :)
@sksin28 can you send me whole page. I m still not able to figure out. please help
@rasanu This is how I got it going in my case.
class MyList extends Component {
constructor(props) {
super(props);
let list = [{name:'a', selected:false}, {name:'b', selected:false}, {name:'c', selected:false}];
const { width } = Dimensions.get('window');
this._dataProvider = new DataProvider((r1, r2) => {
return r1.name !== r2.name || (r1.name === r2.name && r1.selected !== r2.selected);
});
this._layoutProvider = new LayoutProvider(
index => {
return 1;
},
(type, dim) => {
dim.width = width;
dim.height = 120;
}
);
this.state = {
list,
dataProvider: this._dataProvider.cloneWithRows(list)
};
}
_rowRenderer(type, item) {
return (
<View>
<CardItem>
<Body>
<Text>{item.name}</Text>
</Body>
<Right>
<CheckBox checked={!!item.selected} onPress={this.checkboxSelect.bind(this, item)} />
</Right>
</CardItem>
</View>
);
}
checkboxSelect(item) {
this.setState(prevState => {
return {
list: _.map(prevState.list, listItem => {
if (listItem.name === item.name) {
return {
...listItem,
selected: !listItem.selected
};
}
return listItem;
})
};
});
}
render() {
return (
<RecyclerListView
layoutProvider={this._layoutProvider}
dataProvider={this.state.dataProvider.cloneWithRows(this.state.list)}
rowRenderer={this._rowRenderer.bind(this)}
/>
);
}
}
@sksin28 thnx... .. by analysing from previous post code i did it yesterday ... By the way thankx.. for replying bro馃槉
Hello there !! i am new in react native and i am using recyclerlistview. i am trying to update my row in real time but it is not working unless i scroll down and then go up. Please help me out here. i will be very thankful !!
Here is the file--
Most helpful comment
@sksin28 The problem is, you're mutating the object directly, instead of making a new object. That means that the reference is the same
And when the
rowHasChangesruns, it won't see that there are any changes.Instead, you should be making a new object
So, in your code: