我有一个对象,正如你在图片中看到的那样,当我在console.log()它时,在第一行中它表示course是一个0长度的数组。当我扩展它时,它表示长度为1,当我做course.length它说0. Object.keys(course).length也说0。
我在我的应用中做的是,我有一个列表视图。 listview上的每个项目都是可扩展的。每个项目都是一个容器,每个容器都有课程。我从远程服务器获得容器和课程。一切都很完美。现在我正试图从本地数据库加载数据。它不再工作了......
请参阅我的简化代码:
export default class Main extends Component{
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
})
};
}
componentWillMount(){
this.fetchData();
}
fetchData(){
let data = fetch..... //// fetches data
let dsource = {};
for(let i=0; i < data.containers.length; i++){
let container = data.containers[i];
dsource[i] = {
containerId: containder.id,
course: [],
}
for(let x=0; x < container.courses.length; x++){
let course = container.courses[x];
dsource[i].course.push({
courseId: course.id,
courseName: course,name
});
}
}
this.setState({
dataSource: this.state.dataSource.cloneWithRows(dsource)
});
}
&#13;
我读了很多关于stackoverflow的问题,很多文章,但没有成功:( Object.keys(Obj)。length Obj.length all返回0。 有些人说,因为Obj.length只会显示可枚举的属性。我尝试使用Object.defineproperty向对象添加可枚举属性,但没有更改。
任何解决方案?任何帮助都非常感谢。
整个代码(本机反应):
"use strict";
import React, {Component, PropTypes} from 'react';
import {
ActivityIndicator,
ListView,
StyleSheet,
Text,
View,
Image,
NetInfo,
AlertIOS,
TouchableOpacity,
ScrollView,
Dimensions,
} from 'react-native';
let SQLite = require('react-native-sqlite-storage');
let Loading = require("./Loading");
let Accordion = require('react-native-accordion');
let DeviceInfo = require('react-native-device-info');
import Icon from 'react-native-vector-icons/Ionicons';
import { Actions } from 'react-native-router-flux';
import I18n from 'react-native-i18n';
import translations from './translations';
I18n.fallbacks = true;
let LOADING = {};
import CodePush from "react-native-code-push";
let { width, height } = Dimensions.get('window');
let db = SQLite.openDatabase({name : "oc.db", location: 'default'});
export default class Courses extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: false,
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
isConnected: true,
dataLoaded: 0,
restartAllowed: true
};
}
toggleAllowRestart() {
this.state.restartAllowed
? CodePush.disallowRestart()
: CodePush.allowRestart();
this.setState({ restartAllowed: !this.state.restartAllowed });
}
sync() {
CodePush.sync(
{
installMode: CodePush.InstallMode.IMMEDIATE,
updateDialog: false
},
);
}
componentWillMount() {
NetInfo.isConnected.fetch().then(isConnected => {
this.setState({
isConnected: isConnected
});
});
NetInfo.isConnected.addEventListener(
'change',
isConnected => {
this.setState({
isConnected: isConnected
});
}
);
this.fetchData();
this.sync();
}
componentWillReceiveProps() {
this.fetchData();
this.setState({
keyForCourse: Date()
});
if(this.props.goto == 'register'){
Actions.register({type: 'reset'});
}
}
fetchData() {
console.log('Courses: fetchData running');
if(this.state.isConnected == 'wifi' || this.state.isConnected == 'cell' || this.state.isConnected == 'true' || this.state.isConnected){
this.setState({
isLoading: true,
});
db.transaction((tx) => {
tx.executeSql("SELECT * FROM users WHERE active=?",['yes'], (tx, results) => {
let len = results.rows.length;
let row = results.rows.item(0);
let userName = row.userName;
let userMail = row.userMail;
let userId = row.userId;
///// Getting courses list
db.transaction((tx) => {
tx.executeSql("SELECT * FROM containersC WHERE userId=?",[userId], (tx, results) => {
let dsource = {};
let len = results.rows.length;
if(len > 0){
for(let ind = 0; ind < len; ind++ ){
let cntr = results.rows.item(ind);
dsource[ind] = {
nid: cntr.nid,
title: cntr.title,
course: [],
courses: {},
};
//// Get courses for each container
db.transaction((tx) => {
tx.executeSql("SELECT * FROM courses WHERE userId=? AND container_nid=?",[userId, cntr.nid], (tx, results) => {
let lenc = results.rows.length;
if(lenc > 0){
for(var j=0; j < lenc; j++){
let crs = results.rows.item(j);
console.log('Course:', crs);
dsource[ind].course.push({
course_id: crs.course_id,
title: crs.title,
cost: crs.cost,
status: crs.status,
period: crs.period // .time_sys
});
dsource[ind].courses[j] = {
course_id: crs.course_id,
title: crs.title,
cost: crs.cost,
status: crs.status,
period: crs.period // .time_sys
};
}
dsource[ind].total = lenc;
}
}, function(){
console.log('Courses: Something went wrong Line 142');
});
});
//// End getting courses for containers
}
this.setState({
dataSource: this.state.dataSource.cloneWithRows(dsource),
isLoading: false,
dataLoaded: len
});
}
}, (err)=>{
console.log('Courses: Something went wrong', err);
});
}
);
//// End getting courses list
}, function(){
console.log('Courses: Unable to select users from database');
});
});
} else {
AlertIOS.alert(
I18n.t("no_connection_title"),
I18n.t("no_connection_desc")
);
}
}
selectRow(d, n) {
Actions.cdetails({cid: d, tit: n});
//Actions.rdetails({cid: d, tit: n});
}
renderRow(data) {
let header = (
<View style={{ backgroundColor: '#fff', margin: 7, marginBottom: 0 }}>
<View style={styles.rowContainer}>
<View style={styles.textContainer}>
<Icon name="ios-arrow-up" color="#00a2dd" size={30}></Icon>
<Text style={styles.title}>{data.title}</Text>
</View>
</View>
</View>
);
let headerOpen = (
<View style={{ backgroundColor: '#fff', margin: 7, marginBottom: 0 }}>
<View style={styles.rowContainer}>
<View style={styles.textContainer}>
<Icon name="ios-arrow-down" color="#00a2dd" size={30}></Icon>
<Text style={styles.title}>{data.title}</Text>
</View>
</View>
<View style={styles.separator}></View>
</View>
);
///////////
let cid = [];
let content = [];
let cll = data.total;
console.log('Data to render :', data);
console.log('Courses to render :', data.course);
for(let x=0; x < cll; x++){
cid[x] = data.course[x].course_id;
let courseCost;
switch(data.course[x].cost){
case 0:
courseCost = I18n.t("course_fee_free");
break;
case 1:
courseCost = data.course[x].cost;
break;
}
content.push(
<TouchableOpacity key={cid[x]} onPress={()=>{this.selectRow(data.course[x].course_id, data.course[x].title)}} >
<View style={[styles.cardContainer, {marginBottom: 5}, x == 0 ? { paddingTop: 6, } : {}, x == (cll+1) ? { marginBottom: 3} : {}]} key={cid[x]} >
<View style={styles.card}>
<View resizeMode="cover" style={styles.cardTitleContainer}>
<Text style={styles.cardTitle}>{data.course[x].title}</Text>
</View>
<View
style={{
padding : 15,
}}
>
<Text style={styles.cardContent}>
<Icon name="ios-calendar" color="#00a2dd" size={10}> {data.course[x].period}</Icon>{'\n'}
<Icon name="ios-pricetag" color="#00a2dd" size={10}> {courseCost}</Icon>
</Text>
</View>
</View>
</View>
</TouchableOpacity>
);
}
let clist = (
<ScrollView style={styles.scrollView}>
<View style={{
padding: 6,
paddingBottom: 0,
borderTopColor: '#fff',
backgroundColor: '#fff',
margin: 7,
marginTop: 0,
}}>{content}</View>
</ScrollView>
);
////////////
return (
<Accordion
header={header}
headerOpen={headerOpen}
content={clist}
easing="easeOutCubic"
underlayColor="#ebebeb"
/>
);
}
render() {
let content= null;
if(this.state.isLoading){
content = <Loading/>;
} else {
if(this.state.dataLoaded < 1){
content = <View style={styles.errorContainer}>
<View style={styles.error}>
<Text style={styles.Errortext}>
{I18n.t("courses_no_course_available")}
</Text>
</View>
</View>;
} else {
content = <View style={{
flex: 1
}}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}
/>
</View>;
}
}
return (
<View style={styles.container}>
{content}
</View>
);
}
}
let styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "white",
flexDirection: "column",
justifyContent: "center",
backgroundColor: '#e4e7ea',
},
separator: {
height: 1,
backgroundColor: "#d0d1d3",
},
scrollSpinner: {
marginVertical: 20,
},
cardContainer:{
flex: 1,
alignItems: 'stretch',
paddingLeft: 6,
paddingRight: 6,
borderColor: '#d0d1d3',
borderWidth: 1,
borderRadius: 5
},
card:{
flex: 1,
backgroundColor: '#ffffff',
borderRadius: 2,
borderColor: '#ffffff',
borderWidth: 1,
/*shadowColor: 'rgba(0, 0, 0, 0.12)',
shadowOpacity: 0.8,
shadowRadius: 2,
shadowOffset: {
height: 1,
width: 2,
},
*/
},
cardTitleContainer:{
flex: 1,
height: 35,
},
cardTitle:{
position: 'absolute',
top: 5,
left: 5,
backgroundColor: 'transparent',
padding: 10,
fontSize: 12,
color: '#4c4b4b',
fontWeight: 'bold',
},
rowContainer: {
flexDirection: 'column',
padding: 5,
},
textContainer: {
flexDirection: 'row',
flex: 1,
padding: 5
},
title: {
paddingTop: 7,
paddingLeft: 5,
color: '#00a2dd'
},
errorContainer: {
flex: 1,
flexDirection: "column",
backgroundColor: '#e4e7ea',
alignItems: 'center',
},
error: {
marginTop: 75,
width: width -150,
height: 100,
borderRadius: 15,
backgroundColor: '#ecebeb',
alignItems: 'center',
justifyContent: 'center',
},
Errortext: {
color: '#757575'
},
});
Courses = CodePush(Courses);
&#13;
答案 0 :(得分:4)
有3个因素可能导致您描述的一般行为。在你的情况下,我认为它是第一个:
当您调用console.log(x)
时,Chrome控制台会显示当时对象x
的摘要。但是,展开对象时,会再次获取该值。您看到的详细对象自调用console.log()
后可能已更改,更改将显示在详细信息中。
属性可能属于对象的原型(而不是&#34;拥有&#34;属性):
> x = {a:1}
{ a: 1 }
> y = Object.create(x)
> y.a
1
> y
{}
> Object.keys(y)
[]
属性可能是不可枚举的,并且不会显示在关键列表中。 length
是一个不可枚举的属性。
答案 1 :(得分:0)
正如您所说,Object.keys指的是可枚举的属性。数组的“长度”属性(也是一个对象)根本不可枚举。
答案 2 :(得分:0)
试试这个,
const keys =[];
const person = {
name : 'Jobelle',
age :22,
mob :8547391599
}
Object.getOwnPropertyNames(tempObj).forEach(prop => {
keys.push(prop);
});