React Native ListView 不会通过单击重新呈现状态更改
React Native ListView not re-rendering on state change by click
这是我的示例代码,我希望在单击时更新 ListView
元素。
这一行定义样式:
(this.state.selectedField.id==field.id)?'green':'white'
在此示例中,活动 View
应以绿色突出显示。状态正在 handleClick()
内更新,但未调用 renderField()
方法。
如何让 ListView 在点击触发状态改变时重新渲染?
import React, {Component} from 'react';
import {
AppRegistry,
View,
ListView,
Text,
TouchableOpacity
} from 'react-native';
class SampleApp extends Component {
constructor(props) {
super(props);
var ds = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
});
this.state = {
fields: ds.cloneWithRows([
{id:0},{id:1},{id:2}
]),
selectedField: {id:0}
};
}
handleClick(field) {
console.log("Selected field:",field);
this.setState({
selectedField: field
});
}
renderField(field) {
return (
<TouchableOpacity onPress={this.handleClick.bind(this, field)} >
<View style={{backgroundColor:(this.state.selectedField.id==field.id)?'green':'white'}}>
<Text style={{left:0, right:0, paddingVertical:50,borderWidth:1}}>{field.id}</Text>
</View>
</TouchableOpacity>
);
}
render() {
return (
<View>
<ListView
dataSource={this.state.fields}
renderRow={this.renderField.bind(this)}
/>
</View>
);
}
}
AppRegistry.registerComponent('SampleApp', () => SampleApp);
已经回答了很多次,如果你想改变道具上的行渲染,如果你想更新行,这个道具需要进入你的数据。
查看这 2 个答案:
这是我对问题的解决方案,但处理每次点击仍然需要很长时间:
handleClick(field) {
newFields = this.state.fields.map( (x) => x.key === field.key && x.active !== true ? {...x,active:true} : {...x,active:false})
this.setState({
fields:newFields,
dataSource: this.state.dataSource.cloneWithRows(newFields)
});
}
列表在数据源改变时再次呈现,在你的例子中,因为数据源永远不会改变,列表视图永远不会重新呈现。这可以通过在状态变量中添加一个字段来保存数据源的数据来实现。在 componentDidMount 方法中,让 dataSource 克隆带有数据状态变量的行。每当您想要重新呈现列表视图时,您只需更改数据状态变量,列表将自动重新呈现。我已经更改了您的数据,以便为每个对象添加一个选定状态。这是更新后的代码。
class SampleApp extends Component {
constructor(props) {
super(props);
var ds = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
});
var dataVar = [
{
id:0,
selected: true,
},{
id:1,
selected: false,
},{
id:2,
selected: false,
}
];
this.state = {
data: dataVar,
fields: ds,
};
}
componentDidMount() {
this.setState({
fields: this.state.fields.cloneWithRows(dataVar)
});
}
handleClick(field) {
console.log(field);
field.selected = !field.selected;
var dataClone = this.state.data;
console.log(dataClone);
dataClone[field.id] = field;
this.setState({
data: dataClone,
});
}
renderField(field) {
let color = (field.selected == true)?'green':'white';
return (
<TouchableOpacity onPress={this.handleClick.bind(this, field)} >
<View style={{backgroundColor:color}}>
<Text style={{left:0, right:0, paddingVertical:50,borderWidth:1}}> {field.id}</Text>
</View>
</TouchableOpacity>
);
}
render() {
return (
<View>
<ListView
dataSource={this.state.fields}
renderRow={(field) => this.renderField(field)}
/>
</View>
);
}
}
这是一个有效的 rnplay sample
这是我的示例代码,我希望在单击时更新 ListView
元素。
这一行定义样式:
(this.state.selectedField.id==field.id)?'green':'white'
在此示例中,活动 View
应以绿色突出显示。状态正在 handleClick()
内更新,但未调用 renderField()
方法。
如何让 ListView 在点击触发状态改变时重新渲染?
import React, {Component} from 'react';
import {
AppRegistry,
View,
ListView,
Text,
TouchableOpacity
} from 'react-native';
class SampleApp extends Component {
constructor(props) {
super(props);
var ds = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
});
this.state = {
fields: ds.cloneWithRows([
{id:0},{id:1},{id:2}
]),
selectedField: {id:0}
};
}
handleClick(field) {
console.log("Selected field:",field);
this.setState({
selectedField: field
});
}
renderField(field) {
return (
<TouchableOpacity onPress={this.handleClick.bind(this, field)} >
<View style={{backgroundColor:(this.state.selectedField.id==field.id)?'green':'white'}}>
<Text style={{left:0, right:0, paddingVertical:50,borderWidth:1}}>{field.id}</Text>
</View>
</TouchableOpacity>
);
}
render() {
return (
<View>
<ListView
dataSource={this.state.fields}
renderRow={this.renderField.bind(this)}
/>
</View>
);
}
}
AppRegistry.registerComponent('SampleApp', () => SampleApp);
已经回答了很多次,如果你想改变道具上的行渲染,如果你想更新行,这个道具需要进入你的数据。
查看这 2 个答案:
这是我对问题的解决方案,但处理每次点击仍然需要很长时间:
handleClick(field) {
newFields = this.state.fields.map( (x) => x.key === field.key && x.active !== true ? {...x,active:true} : {...x,active:false})
this.setState({
fields:newFields,
dataSource: this.state.dataSource.cloneWithRows(newFields)
});
}
列表在数据源改变时再次呈现,在你的例子中,因为数据源永远不会改变,列表视图永远不会重新呈现。这可以通过在状态变量中添加一个字段来保存数据源的数据来实现。在 componentDidMount 方法中,让 dataSource 克隆带有数据状态变量的行。每当您想要重新呈现列表视图时,您只需更改数据状态变量,列表将自动重新呈现。我已经更改了您的数据,以便为每个对象添加一个选定状态。这是更新后的代码。
class SampleApp extends Component {
constructor(props) {
super(props);
var ds = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
});
var dataVar = [
{
id:0,
selected: true,
},{
id:1,
selected: false,
},{
id:2,
selected: false,
}
];
this.state = {
data: dataVar,
fields: ds,
};
}
componentDidMount() {
this.setState({
fields: this.state.fields.cloneWithRows(dataVar)
});
}
handleClick(field) {
console.log(field);
field.selected = !field.selected;
var dataClone = this.state.data;
console.log(dataClone);
dataClone[field.id] = field;
this.setState({
data: dataClone,
});
}
renderField(field) {
let color = (field.selected == true)?'green':'white';
return (
<TouchableOpacity onPress={this.handleClick.bind(this, field)} >
<View style={{backgroundColor:color}}>
<Text style={{left:0, right:0, paddingVertical:50,borderWidth:1}}> {field.id}</Text>
</View>
</TouchableOpacity>
);
}
render() {
return (
<View>
<ListView
dataSource={this.state.fields}
renderRow={(field) => this.renderField(field)}
/>
</View>
);
}
}
这是一个有效的 rnplay sample