【问题标题】:Differentiate between the previous element and current element from the data of a Flatlist in react native从反应原生的Flatlist的数据中区分前一个元素和当前元素
【发布时间】:2017-09-22 15:29:19
【问题描述】:

我正在尝试使用 react native 构建一个聊天应用程序。我正在使用 flatlist 列出对话的消息。

export default class ExampleConversation extends React.Component {
    _renderItem = ({item}) => {
        return (
            <View style={{backgroundColor: 'white', margin: 4, flexDirection: 'row'}}>
                <Text>{item.sender.id}</Text>
                <Text>{item.body}</Text>
            </View>
        )
    };

    render() {
        return <FlatList
                    data={data}
                    renderItem={this._renderItem}
                    keyExtractor={(item, id) => item.id}
                    style={styles.container}
                    inverted={true}/>
    }
}

从服务器获取的 JSON 数据:

const data = [
    {
        "id": 13,
        "sender_id": 1,
        "body": "Some message"
    },
    {
        "id": 12,
        "sender_id": 1,
        "body": "Some message"
    },
    {
        "id": 11,
        "sender_id": 5,
        "body": "Some message"
    }
];

从上面的数据可以看出,第一条和第二条消息都来自同一个发件人(sender_id: 1)。当上一条消息和当前消息来自同一发件人时,我想删除该消息对象的&lt;Text&gt;{sender_id}&lt;/Text&gt;

    return (
        <View style={{backgroundColor: 'white', margin: 4, flexDirection: 'row'}}>
            <Text>{item.body}</Text>
        </View>
    )

基本上,我想通过检查为 Flatlist 数据提供的元素来更改 Message 组件的布局,就像 facebook messenger 显示其消息的方式一样。

如何通过 Flatlist 数据的键值区分先前元素和当前元素?

【问题讨论】:

    标签: reactjs user-interface react-native react-native-flatlist


    【解决方案1】:

    Flatlist 的renderItem 属性为当前渲染项提供index 属性。您可以使用索引查找上一个项目的发件人是否相同。要实现这种行为,您需要对数据进行排序。

    举例

    const data = [
        {
            "id": 13,
            "sender_id": 1,
            "body": "Some message",
            "sentDate": 00003,
        },
        {
            "id": 12,
            "sender_id": 1,
            "body": "Some message"
            "sentDate": 00002,
        },
        {
            "id": 11,
            "sender_id": 5,
            "body": "Some message"
            "sentDate": 00001,
        }
    ];
    
        isSenderSame = ({currentMessage, prevMessage}) => {
          return currentMessage.sender_id === prevMessage.sender_id;
        }
        _renderItem = ({item, index}) => {
            const style = isSenderSame(item, this.state.data[(index - 1)]) ? styles.sameMessageStyle : styles.differentMessageStyle;
            return (
                <View style={[{backgroundColor: 'white', margin: 4, flexDirection: 'row'}, style]}>
                    <Text>{item.sender.id}</Text>
                    <Text>{item.body}</Text>
                </View>
            )
        };
    
        render() {
            return <FlatList
                        data={this.state.data}
                        renderItem={this._renderItem}
                        keyExtractor={(item, id) => item.id}
                        style={styles.container}
                        inverted={true}/>
        }
    

    更新

    另一种方法是让服务器对数据进行排序。您可以在块中发送消息并在renderItem 中使用循环呈现它们

    const data = [{
        "sender_id": 5,
        "messages": [{
            "id": 14,
            "body": "Some message"
            "sentDate": 00006
        }]
    }, {
        "sender_id": 1,
        "messages": [{
            "id": 13,
            "body": "Some message",
            "sentDate": 00003
        }, {
            "id": 12,
            "body": "Some message"
            "sentDate": 00002,
        }]
    }, {
        "sender_id": 5,
        "messages": [{
            "id": 11,
            "body": "Some message"
            "sentDate": 00001
        }]
    }]
    

    【讨论】:

    • 是的,我也这么认为。但我害怕表演。如果我检查大数据集的索引,它不会影响性能吗?
    • @Kakar 很抱歉,但我无法对此发表评论,因为我从未尝试过。但是,如果我真的需要猜测这并不重要,因为无论您希望 FlatList 性能如何,您都将在块中渲染项目。回答此类问题的最佳方法是尝试并查看。
    • @bennygenel 我已经按照你上面所说的那样实现了我的 FlatList 数据,非常好:)
    【解决方案2】:

    一种方法可以是这样,当您向数据添加新对象时,也添加其索引,例如,

    let data = this.state.data;
    let length = data.length;
    this.setState({
      data:[...data, {...yourData, index:length+1}] //using ES6 spread operator
    });
    

    现在在你的 renderItem 函数中尝试类似

    let {index, id, sender_id} = item //using object destruction
    let lastMessage = this.state.data[index-1];
    let isSame = (sender_id === lastMessage. sender_id)?true:false; //use it 
    

    ***** 必须有比这更高效的方法。

    【讨论】:

    • 是的,我也这么认为。但我也害怕表演。我担心如果我检查大型数据集的索引会影响性能?
    • 好吧,你应该看看github.com/FaridSafi/react-native-gifted-chat的源代码,你可能会发现一些你的用例
    【解决方案3】:

    除了在渲染中包含逻辑之外,您还可以在获取数据时只循环一次,然后将结果提供给您的平面列表:

    .then((data) => {
      const messages = data.map((item, index) => {
        if (index > 0) {
          return (item.sender_id === data[index].sender_id) ? { //return object without sender id } : item;
        }
      })
      this.setState({ data: messages });
    })
    

    【讨论】:

    • 所以每次数据发生变化,都要重新循环遍历数据数组,对性能不好
    • 不..只有一次api请求成功后。要么,要么你总是可以将 api 修改为这个逻辑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-18
    • 1970-01-01
    • 2016-04-25
    • 2015-06-11
    • 1970-01-01
    • 2022-08-06
    相关资源
    最近更新 更多