dataSource更新后,ListView不会重新呈现

时间:2017-07-09 22:55:51

标签: javascript listview firebase react-native firebase-realtime-database

我正在尝试使用addTodo,removeTodo,markCompleted todos等功能实现一个反应原生的todo应用程序。添加待办事项后,当我按下markComplete文本时,listView不会重新渲染,如果我重新加载应用程序,它会显示预期结果。我正在使用Firebase数据库从我这里获取我的待办事项。

基本上,当我点击markComplete时,我正在更新listView数据源中的属性。每当我按下UI上的markComplete或Completed按钮时,一切都工作正常,期望重新呈现listView。我已经尝试了相关问题中提出的一些解决方案,我无法使其正常工作。

更具体一点:请查看以下代码注释//当todo更改时。当我更改items数组中的某些内容时,我正在更新这些代码行中的数据源。

以下是我的应用UI的代码和快照。

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  ListView,
  Text,
  View,
  TouchableHighlight,
  TextInput
} from 'react-native';

var Firebase = require('firebase');

class todoApp extends Component{
  constructor(props) {
  super(props);
  var myFirebaseRef = new Firebase('[![enter image description here][1]][1]database URL');
  this.itemsRef = myFirebaseRef.child('items');

  this.state = {
    newTodo: '',
    completed: false,
    todoSource: new ListView.DataSource({rowHasChanged: (row1, row2) => row1 !== row2})
  };
  this.handleKey = null;
  this.items = [];
} // End of Constructor

componentDidMount() {
  // When a todo is added
  this.itemsRef.on('child_added', (dataSnapshot) => {
    this.items.push({
       id: dataSnapshot.key(),
       text: dataSnapshot.child("todo").val(), 
       completedTodo: dataSnapshot.child("completedTodo").val()
      });
    this.setState({
      todoSource: this.state.todoSource.cloneWithRows(this.items)
    });
  });

  // When a todo is removed
  this.itemsRef.on('child_removed', (dataSnapshot) => {
      this.items = this.items.filter((x) => x.id !== dataSnapshot.key());
      this.setState({
        todoSource: this.state.todoSource.cloneWithRows(this.items)
      });
  });

  // When a todo is changed
  this.itemsRef.on('child_changed', (dataSnapshot) => {
    this.items.forEach(function (value) {
    if(value["id"] == this.handleKey){

    this.items["value"]["completedTodo"]= dataSnapshot.child("completedTodo").val()
    }
    });
    this.setState({
      todoSource: this.state.todoSource.cloneWithRows(this.items)
    });
  });
}



addTodo() {
  if (this.state.newTodo !== '') {
    this.itemsRef.push({
      todo: this.state.newTodo,
      completedTodo: this.state.completed,
    });
    this.setState({
      newTodo : ''
    });
  }

console.log(this.items);
}
removeTodo(rowData) {
  this.itemsRef.child(rowData.id).remove();
}

handleCompleted(rowData){
  this.handleKey = rowData.id;
  if(rowData.completedTodo){

    this.itemsRef.child(rowData.id).update({
      completedTodo: false
    })
  }
  if(rowData.completedTodo == false){
    this.itemsRef.child(rowData.id).update({
      completedTodo: true
    })
  }

}

renderRow(rowData) {
  return (
      <View>
        <View style={styles.row}>
          <TouchableHighlight
          underlayColor='#dddddd'
          onPress={() => this.removeTodo(rowData)}>
          <Text style={styles.todoText}>{rowData.text}</Text>
          </TouchableHighlight>
          <TouchableHighlight underlayColor='#dddddd' onPress={() => this.handleCompleted(rowData)}>
          {rowData.completedTodo? <Text style={styles.todoText}>Completed</Text>:<Text style={styles.todoText}>MarkCompleted</Text>}
          </TouchableHighlight>
        </View>
        <View style={styles.separator} />
      </View>

  );
}


render() {
  return (
    <View style={styles.appContainer}>
      <View style={styles.titleView}>
        <Text style={styles.titleText}>
          My Todos
        </Text>
      </View>
      <View style={styles.inputcontainer}>
        <TextInput style={styles.input} onChangeText={(text) => this.setState({newTodo: text})} value={this.state.newTodo}/>
        <TouchableHighlight
          style={styles.button}
          onPress={() => this.addTodo()}
          underlayColor='#dddddd'>
          <Text style={styles.btnText}>Add!</Text>
        </TouchableHighlight>
      </View>
      <ListView
        dataSource={this.state.todoSource}
        renderRow={this.renderRow.bind(this)} />
    </View>
  );
}


} // Main Class End

UI Snapshot

1 个答案:

答案 0 :(得分:0)

确保创建新对象,而不是更新现有对象的属性。

  

如果要更新listView,请创建新对象而不是更新   现有对象的属性。

以下代码解决了Github上的类似问题。

let newArray = oldArray.slice();
newArray[indexToUpdate] = {
  ...oldArray[indexToUpdate],
  field: newValue,
};
let newDataSource = oldDataSource.cloneWithRows(newArray);

有关详细说明,This answer可能会对您有所帮助。