2016-02-15 49 views
9

我知道這已經被問過,例如參見here,herehereReact原生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將工作出於某種原因。如果你以正確的方式開始,你應該使用類似於:

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

當更新你的dataSource

還請記住,您需要新的rows datablob。用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

您還可以使用ROWID在renderRow以確定要刪除的項目,然後在你的刪除功能,重新設置數據源的狀態。

查看我設置的示例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網站上的電影教程以及ListView的文檔按照我所做的方式設置了新狀態,使用'dataSource:this.state.dataSource.cloneWithRows',所以我想我沒有想到按照你的方式去做之前。再次,謝謝! –

+0

真棒,是在ListView的文檔是好的,但他們不是他們最好的。我現在正在處理一個請求,希望他們會認爲這很有道理! –

+0

我剛剛注意到,使用上面描述的方法,'rowHasChanged'沒有被調用。您可以通過在其中放置控制檯日誌來驗證它。這不可能是預期的行爲,可以嗎?正如我所說,React Native文檔使用'this.state.dataSource.cloneWithRows'更新狀態,而不是在某些全局'ds'對象上使用'ds.cloneWithRows'。 –