2016-02-15 13 views
9

これは以前に尋ねられたことが分かりました。例えば、herehereおよびhereを参照してください。React Native ListView:削除時に間違った行が削除される

しかし、回答/コメントはいずれも満足できるものではありません。彼らは、問題を解決しないデータを複製するか、または問題を解決するが、新しいものを作成するListViewに一意のキーを設定するように指示します。

ListViewに一意のキーを設定し、削除後に更新すると、ビュー全体が再びレンダリングされ、上にスクロールされます。アイテムを削除するためにリストを下にスクロールしたユーザは、リストがその位置を維持することを期待する。

var ListViewExample = React.createClass({ 

    getInitialState() { 
    var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => { 
     r1 !== r2 
    }}); 
    var rows = ['row 1', 'row 2', 'row 3']; 
    return { 
     dataSource: ds.cloneWithRows(rows), 
    }; 
    }, 

    _deleteRow() { 
    var rows = ['row 1', 'row 3']; 
    this.setState({dataSource: this.state.dataSource.cloneWithRows(rows)}) 
    }, 

    renderRow(rowData, sectionID, rowID) { 
    return <TouchableOpacity onPress={this._deleteRow} 
     style={{height: 60, flex: 1, borderBottomWidth: 1}}> 
     <Text>{rowData}</Text> 
    </TouchableOpacity> 
    }, 

    render() { 
    return (
     <ListView 
     dataSource={this.state.dataSource} 
     renderRow={this.renderRow} 
     /> 
    ); 
    } 

}); 

そしてhereあなたは間違った行取得者が削除アクションでそれのGIF画像を見ることができます:

は、ここで私は、データを複製するのが正しい方法だった引き受けるものを使用して、不自然な例です。代わりに、ListViewのkey小道具を設定すると、正しい行が削除されますが、私が言ったように、リストが上にスクロールする原因になります。

UPDATE

私はすでに以下のネーダーの答えを受け入れてきましたが、これは、それがデータソースにrowHasChangedを呼び出すことはありませんので、正しい方法ではないようです。また、ListViewのドキュメントにも準拠していません。私はそれを残しておきますので、それはオーケー、これは厄介ですが、私のrowHasChanged機能だった答えとしてマークされたが、私は、これは回避策ではなく、正しい解決策

別の更新

ある感じを持っている私の問題を解決しましたreturnステートメントがありません。私のコーヒーにはES6の砂糖が多すぎますね。

あなたrowHasChanged機能を台無しにあれば結論で、this._dsは、何らかの理由で動作します。あなたのdataSourceを更新する際

this.setState({ 
    dataSource: this.state.dataSource.cloneWithRows(rows) 
}); 

:あなたは物事を行う場合に開始する正しい方法は、おそらくのようなものを使用する必要があります。

また、新しいrowsデータ欄が必要であることを覚えておいてください。 cloneWithRows(rows.push(newRow)のようなものでそれを突然変異させることはできませんが、cloneWithRows(rows.concat([newRow])となります。

+0

それが助け場合は他の誰か...私は...クローニング前に私のリストのディープコピーを作っていたため、キーのでcloneWithRowsを行う前にnew_rows = [...行] –

答えて

5

私は問題は、以前のListView.DataSourceインスタンスに基づいてデータソースを設定していることだと思います。私がhereについて話していることのデモをセットアップし、これを実行する別の方法と一緒に例を下に置いておきます。

'use strict'; 

var React = require('react-native'); 
var { 
    AppRegistry, 
    StyleSheet, 
    Text, 
    View, 
    TouchableOpacity, 
    ListView 
} = React; 

var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => { r1 !== r2 }}); 

var SampleApp = React.createClass({ 

    getInitialState() { 
    var rows = ['row 1', 'row 2', 'row 3']; 
    return { 
     dataSource: ds.cloneWithRows(rows), 
    }; 
    }, 

    _deleteRow() { 
    var rows = ['row 1', 'row 3']; 
    this.setState({dataSource: ds.cloneWithRows(rows)}) 
    }, 

    renderRow(rowData, sectionID, rowID) { 
    return <TouchableOpacity onPress={this._deleteRow} 
     style={{height: 60, flex: 1, borderBottomWidth: 1}}> 
     <Text>{rowData}</Text> 
    </TouchableOpacity> 
    }, 

    render() { 
    return (
     <ListView 
     dataSource={this.state.dataSource} 
     renderRow={this.renderRow} 
     /> 
    ); 
    } 

}); 

https://rnplay.org/apps/YGBcIA

ます。また、データソースの状態をリセットし、その後、あなたの削除機能では、削除したい項目を識別するためにrenderRowでROWIDを使用することができます。

はこれをやってみてください。

hereを設定した例を確認してください。また、以下のコードは次のとおりです。

'use strict'; 

var React = require('react-native'); 
var { 
    AppRegistry, 
    StyleSheet, 
    Text, 
    View, 
    TouchableOpacity, 
    ListView 
} = React; 

var rows = ['row 1', 'row 2', 'row 3']; 
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => { 
     r1 !== r2 
    }}); 

var SampleApp = React.createClass({ 

    getInitialState() { 

    return { 
     dataSource: ds.cloneWithRows([]), 
     rows: rows 
    }; 
    }, 

    componentDidMount() { 
    this.setState({ 
     dataSource: ds.cloneWithRows(this.state.rows) 
    }) 
    }, 

    _deleteRow(rowID) { 
    this.state.rows.splice(rowID, 1) 
    this.setState({ 
     dataSource: ds.cloneWithRows(this.state.rows), 
    }) 
    }, 

    renderRow(rowData, sectionID, rowID) { 
    return <TouchableOpacity onPress={() => this._deleteRow(rowID) } 
     style={{height: 60, flex: 1, borderBottomWidth: 1}}> 
     <Text>{rowData}</Text> 
    </TouchableOpacity> 
    }, 

    render() { 
    return (
     <ListView 
     dataSource={this.state.dataSource} 
     renderRow={this.renderRow} 
     /> 
    ); 
    } 

}); 
var styles = StyleSheet.create({ 
    container: { 
    flex: 1, 
    justifyContent: 'center', 
    alignItems: 'center', 
    backgroundColor: '#F5FCFF', 
    }, 
    welcome: { 
    fontSize: 28, 
    textAlign: 'center', 
    margin: 10, 
    }, 
    instructions: { 
    textAlign: 'center', 
    color: '#333333', 
    fontSize: 19, 
    marginBottom: 5, 
    }, 
}); 

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

あなたは絶対に正しいです。ありがとう! React NativeウェブサイトのMovieチュートリアルとListViewのドキュメントは、 'dataSource:this.state.dataSource.cloneWithRows'を使って、私のやり方で新しい状態を設定しました。私はあなたのやり方を考えなかったと思います前。もう一度、ありがとう! –

+0

素晴らしいです、ええ、リストビューのドキュメントは大丈夫ですが、彼らは最高ではありません。私は現時点でプルの要求に取り組んでいます、うまくいけば彼らはそれが理にかなっていると思うでしょう! –

+0

私は、上記のメソッドを使って、 'rowHasChanged'が呼び出されないことに気付きました。コンソールにログインして確認することができます。それは意図された行動ではありませんか?私が言ったように、React Nativeのドキュメントは、いくつかのグローバル 'ds'オブジェクトの' ds.cloneWithRows'ではなく、 'this.state.dataSource.cloneWithRows'で状態を更新します。 –