Различать предыдущий элемент и текущий элемент из данных Flatlist в 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). Когда предыдущее сообщение и текущее сообщение от одного и того же отправителя, я хотел бы удалить <Text>{sender_id}</Text> для этого объекта сообщения.

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

По сути, я хотел бы изменить макет компонента Message, проверив элементы, заданные для данных Flatlist, очень похоже на то, как мессенджер facebook отображает свои сообщения.

введите здесь описание изображения

Как я могу различать предыдущий и текущий элементы по его ключевым значениям данных Flatlist?


person Kakar    schedule 22.09.2017    source источник


Ответы (3)


Свойство renderItem Flatlist предоставляет свойство 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
    }]
}]
person bennygenel    schedule 22.09.2017
comment
Да, я тоже так думал. Но я боюсь за исполнение. Не повлияет ли это на производительность, если я проверю индекс большого набора данных? - person Kakar; 22.09.2017
comment
@Kakar Извините, но я не могу это комментировать, так как никогда не пробовал. Но если мне действительно нужно угадать, это не будет иметь большого значения, поскольку вы будете отображать элементы в блоке, независимо от того, что, если вы хотите, чтобы ваш FlatList работал хорошо. Лучший способ ответить на такого рода вопросы — попробовать и посмотреть. - person bennygenel; 22.09.2017
comment
@bennygenel я реализовал свои данные FlatList, как вы сказали выше, это неплохо :) - person redwind; 27.10.2017

Один из подходов может быть таким: когда вы добавляете новый объект в данные, также добавляете его индекс, например,

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 

***** должен быть более эффективный подход, чем этот.

person Manjeet Singh    schedule 22.09.2017
comment
Да, я тоже так думал. Но я тоже боюсь за выступление. Я боюсь, что это повлияет на производительность, если я проверю индекс большого набора данных? - person Kakar; 22.09.2017
comment
хорошо, тогда вам следует заглянуть в исходный код github.com/FaridSafi/react-native- gifted-chat, вы можете найти что-то из своего варианта использования - person Manjeet Singh; 22.09.2017

Вместо того, чтобы иметь логику в рендеринге, вы также можете прокрутить ее только один раз, когда вы извлекаете данные, а затем передаете результат в свой плоский список:

.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 });
})
person Matt Aft    schedule 22.09.2017
comment
Поэтому каждый раз, когда данные изменяются, мы должны снова перебирать массив данных, это не очень хорошо для производительности. - person redwind; 27.10.2017
comment
Нет... это только один раз после успешного запроса API. Либо так, либо вы всегда можете изменить API в соответствии с этой логикой. - person Matt Aft; 28.10.2017