0

私は、toToso、removeTodo、markCompleted todosなどの機能を備えた反応ネイティブでtodoアプリケーションを実装しようとしています。 todosを追加した後、markCompleteテキストを押すと、listViewは再レンダリングされません。アプリケーションをリロードすると、期待される結果が表示されます。私はFirebaseデータベースを使って自分のtodosを取得しています。dataSourceが更新された後にListViewが再レンダリングされない

基本的に、markCompleteをクリックすると、listViewデータソースのプロパティを更新しています。すべてがうまくいきましたUI上のmarkCompleteボタンまたはCompletedボタンを押すたびにlistViewの再レンダリングを期待しています。私は関連する質問で提案されたいくつかのソリューションを試しました、私はそれを働かせるcouldnt。

より具体的には、下記のコードを見てください。// Todoが変更されたとき。私はアイテムの配列で何かを変更すると、コードの行で自分のデータソースを更新しています。

以下は、自分のコードとアプリの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

答えて

0

代わりに、既存のオブジェクトのプロパティを更新する新しいオブジェクトを作成することを確認します。

リストビューを更新する場合は、既存のオブジェクトのプロパティーを更新する代わりに、新しいオブジェクトを作成します。

以下のコードはGithubで同様の問題を解決しました。

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

さらに詳しい説明については、This answerが参考になる場合があります。

+0

私はこの質問を投稿する前にそのコードを試してみました。私はそれがあなたが配列を持っているときに動作しますが、オブジェクトの配列のためにそれは何か異なるものでなければなりません。有益なコードを提供できるなら、それは素晴らしいことです。 – Sameer

+0

私はまだこのListViewの再レンダリングの問題を苦労している、私はもっと多くのソリューションをstackoverflowの他の投稿に提案してみました。このコードで何が間違っているのかを指摘できる人はいますか? – Sameer

関連する問題