0

Ich versuche, eine Todo-App in reaktiven nativen Funktionen wie addTodo, removeTodo, markCompleted Todo zu implementieren. Nach dem Hinzufügen von Todos, wenn ich markComplete Text drücke, wird das listView nicht neu gerendert, wenn ich die App neu lade zeigt es die erwarteten Ergebnisse an. Ich verwende Firebase-Datenbank, um meine Todos zu holen.ListView wird nicht neu gerendert, nachdem dataSource aktualisiert wurde

Grundsätzlich aktualisiere ich eine Eigenschaft in meiner ListView-Datenquelle, wenn ich auf markComplete klicke. Alles funktioniert einwandfrei. Ich erwarte das erneute Rendern von listView immer dann, wenn ich die Schaltflächen "MarkComplete" oder "Completed" auf der Benutzeroberfläche drücke. Ich habe versucht ein paar Lösungen in verwandten Fragen vorgeschlagen, ich könnte es nicht funktionieren.

Um genauer zu sein: Bitte sehen Sie sich den Code unter Kommentar // Wenn ein Todo geändert wird. Ich aktualisiere meine Datenquelle in diesen Codezeilen, wenn ich etwas im Elementarray ändere.

Unten ist mein Code und Snapshot der App 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

Antwort

0

Achten Sie darauf, neue Objekte zu erstellen, anstatt die Eigenschaften vorhandener Objekte zu aktualisieren.

Wenn Sie listView aktualisieren möchten, erstellen Sie neue Objekte, anstatt die Eigenschaften vorhandener Objekte zu aktualisieren.

Der folgende Code löste ein ähnliches Problem auf Github.

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

Für eine detailliertere Erklärung könnte This answer Ihnen helfen.

+0

Ich habe diesen Code vor dem Posten dieser Frage versucht, hat nicht für mich arbeiten. Ich lese es funktioniert, wenn Sie Array haben, aber für Array von Objekten muss es etwas anderes sein. Wenn Sie einen hilfreichen Code zur Verfügung stellen können, wird das großartig. – Sameer

+0

Ich habe immer noch Probleme mit diesem ListView-Problem beim erneuten Rendern. Ich habe viel mehr Lösungen ausprobiert, die in anderen Posts in stackoverflow vorgeschlagen wurden. Gibt es jemanden, der darauf hinweisen kann, was in diesem Code falsch ist? – Sameer

Verwandte Themen