gpt4 book ai didi

listview - 您尝试在一个不可变且已被卡住的对象上设置 key

转载 作者:行者123 更新时间:2023-12-03 13:09:44 27 4
gpt4 key购买 nike

在以下示例中:

  • MapViewListView 的元素显示为注释
  • 点击ListView元素应该会导致将其绘制为蓝色颜色。
  • 如果 MapViewListView 有效地使用状态对象,则会获得奖励

修改ListViewDataSource似乎会在修改active属性时导致冲突:

You attempted to set the key 'active' with the value 'false' on an object that is meant to be immutable and has been frozen.

enter image description here

设置状态的正确方法是什么?

RNPlay Example

'use strict';

import React, {Component} from 'react';
import {AppRegistry,View,ListView,MapView,Text,TouchableOpacity} from 'react-native';

var annotations = [
{
title: 'A',active: false,latitude: 45,longitude: 26,latitudeDelta: 0.015,longitudeDelta: 0.015,
},{
title: 'B',active: false,latitude: 49,longitude: 14,latitudeDelta: 0.015,longitudeDelta: 0.015,
},{
title: 'C',active: false,latitude: 26,longitude: 25,latitudeDelta: 0.015,longitudeDelta: 0.015,
}
]

class SampleApp extends Component {

constructor(props) {
super(props);
var ds = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
});
this.state = {
region: annotations[0],
annotations: annotations,
dataSource: ds.cloneWithRows(annotations)
};
}

handleClick(field) {
if (this.previousField) {
this.previousField.active = false;
}
this.previousField = field;
field.active = true;
this.setState({
region: field,
});
}

renderField(field) {
let color = (field.active == true)?'blue':'yellow';

return (
<TouchableOpacity onPress={this.handleClick.bind(this,field)}>
<Text style={{backgroundColor:color,borderWidth:1}}>{field.title}</Text>
</TouchableOpacity>
);
}

render() {
return (
<View style={{flex:1,flexDirection:'column',alignSelf:'stretch'}}>
<MapView
style={{flex:0.5,alignSelf:'stretch',borderWidth:1}}
region={this.state.region}
annotations={this.state.annotations}
/>
<ListView
dataSource={this.state.dataSource}
renderRow={(field) => this.renderField(field)}
/>
</View>
);
}
}

AppRegistry.registerComponent('SampleApp', () => SampleApp);

最佳答案

问题

当您设置 field.active = true;this.previousField.active = false; 时,您正在修改一个对象(field) 存在于 ListView 的数据源中。 ListView 会引发错误,因为当您使用 cloneWithRows 创建它时,它会卡住其数据源。这是为了确保数据源无法在正常的 React 组件生命周期之外进行修改(例如 setState)。相反,ListView.DataSource 对象被设计为通过 cloneWithRows 进行更改,它返回现有数据源的副本

如果您熟悉 Redux库,它与让reducer函数返回状态的副本的哲学非常相似,而不是修改现有的状态。

克隆数据源

要解决这个问题,您真正想要做的是创建一个已设置值的新数据数组(例如active),然后使用 cloneWithRows 创建的 ListView 的新数据源调用 setState。如果您这样做,实际上您的状态中根本不需要 annotations 键。

这里的代码可能比文字更有帮助:

handleClick(field) {

//iterate over annotations, and update them.
//I'm taking 'title' as a unique id property for each annotation,
//for the sake of the example.
const newAnnotations = annotations.map(a => {
//make a copy of the annotation. Otherwise you'll be modifying
//an object that's in your listView's datasource,
//and therefore frozen.
let copyA = {...a};
if (copyA.title === field.title) {
copyA.active = true;
} else {
copyA.active = false;
}
return copyA;
});

this.setState({
region: {...field, active: true},
dataSource: this.state.dataSource.cloneWithRows(newAnnotations),
});
}

我希望这有帮助!这是一个代码片段,其中包含您发布的完整代码以及我的修改。它对我有用,就像你在 iOS 上使用 React Native 0.29 所描述的那样。您标记了问题 android-mapview,所以我假设您运行的是 Android,但在这种情况下该平台应该不会真正产生影响。

'use strict';

import React, {Component} from 'react';
import {AppRegistry,View,ListView,MapView,Text,TouchableOpacity} from 'react-native';

var annotations = [
{
title: 'A',active: false,latitude: 45,longitude: 26,latitudeDelta: 0.015,longitudeDelta: 0.015,
},{
title: 'B',active: false,latitude: 49,longitude: 14,latitudeDelta: 0.015,longitudeDelta: 0.015,
},{
title: 'C',active: false,latitude: 26,longitude: 25,latitudeDelta: 0.015,longitudeDelta: 0.015,
}
]

class SampleApp extends Component {

constructor(props) {
super(props);
var ds = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
});
this.state = {
region: annotations[0],
dataSource: ds.cloneWithRows(annotations)
};
}

handleClick(field) {

//iterate over annotations, and update them.
//I'm taking 'title' as a unique id property for each annotation,
//for the sake of the example.
const newAnnotations = annotations.map(a => {
//make a copy of the annotation. Otherwise you'll be modifying
//an object that's in your listView's datasource,
//and therefore frozen.
let copyA = {...a};
if (copyA.title === field.title) {
copyA.active = true;
} else {
copyA.active = false;
}
return copyA;
});

this.setState({
region: {...field, active: true},
dataSource: this.state.dataSource.cloneWithRows(newAnnotations),
});
}

renderField(field) {
console.log(field);
let color = (field.active == true)?'blue':'yellow';

return (
<TouchableOpacity onPress={this.handleClick.bind(this,field)}>
<Text style={{backgroundColor:color,borderWidth:1}}>{field.title}</Text>
</TouchableOpacity>
);
}

render() {
return (
<View style={{flex:1,flexDirection:'column',alignSelf:'stretch'}}>
<MapView
style={{flex:0.5,alignSelf:'stretch',borderWidth:1}}
region={this.state.region}
annotations={this.state.annotations}
/>
<ListView
dataSource={this.state.dataSource}
renderRow={(field) => this.renderField(field)}
/>
</View>
);
}
}

AppRegistry.registerComponent('SampleApp', () => SampleApp);

关于listview - 您尝试在一个不可变且已被卡住的对象上设置 key ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38270445/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com