首页 > 解决方案 > React Native Flatlist 在数据更新时多次渲染同一个项目

问题描述

当数据更新时,react native flatlist 组件渲染同一个项目的次数与数据列表一样多。这是一个聊天应用程序。当用户单击发送按钮时, this.state.messages 会更新并导致平面列表重新呈现。但是,当它重新渲染时,所有组件都以相同的方式渲染。

聊天.js

import React, { Component } from 'react';
import { View, FlatList } from 'react-native';
import { connect } from 'react-redux';
import { ChatBubble, Input } from './';

import { Header } from '../header';

class Chat extends Component {
  state={
    messages: [],
  };

  componentWillMount() {
    this.setState({
      messages: [
        {
          text: this.props.navigation.state.params.chat.lastMessage,
          direction: 'left',
          timeStamp: new Date().getTime(),
          id: '666',
          user: {
            displayName: this.props.navigation.state.params.chat.displayName,
          },
        }, {
          text: 'Thanks Nick!',
          timeStamp: new Date().getTime(),
          direction: 'right',
          id: '589',
          user: {
            displayName: 'You',
          },
        },
      ],
    });
  }

  onSend = (message) => {
    const messageData = {
      text: message,
      timeStamp: new Date().getTime(),
      direction: 'right',
      id: Math.random(1000).toString(),
      user: {
        displayName: 'You',
      },
    };
    if (message !== '') {
      this.setState({
        messages: this.state.messages.concat([messageData]),
      });
    }
    setTimeout(() => this.list.scrollToEnd(), 200);
  }

  renderMessages = ({ item }) => {
    return <ChatBubble message={item} />;
  }

  render() {
    return (
      <View style={{ flex: 1, backgroundColor: 'white' }}>
        <Header title={this.props.navigation.state.params.chat.displayName} />
        <FlatList
          keyboardShouldPersistTaps='always'
          data={this.state.messages}
          contentContainerStyle={{ backgroundColor: 'white', justifyContent: 'flex-end', flexGrow: 1 }}
          keyExtractor={message => message.id}
          renderItem={this.renderMessages}
          ref={(ref) => { this.list = ref; }}
        />
        <Input onPress={this.onSend} />
      </View>
    );
  }
}

const mapStateToProps = (state) => {
  let user;
  if (state.user.user) {
    user = state.user.user;
  }
  return { user };
};

export default connect(mapStateToProps)(Chat);

ChatBubble.js

import React, { Component } from 'react';
import { View, Clipboard, Text, TouchableWithoutFeedback } from 'react-native';
import moment from 'moment';

import { colors } from '../../config';

let message;

class ChatBubble extends Component {
  constructor(props) {
    super(props);
     message = this.props.message;
   }

  render() {
    return (
      <View style={styles[message.direction].container}>
        <View style={styles.topContainerStyle}>
          <Text style={styles[message.direction].infoStyle}>
            {message.user.displayName}
          </Text>
          <Text style={styles[message.direction].infoStyle}>
            {moment(message.timeStamp).format('LT')}
          </Text>
        </View>
        <Text style={styles[message.direction].message}>
          {message.text}
        </Text>
      </View>
    );
  }
}

const styles = {
  left: {
    container: {
      borderRadius: 20,
      borderBottomLeftRadius: 0,
      marginTop: 8,
      marginRight: 150,
      marginLeft: 10,
      paddingHorizontal: 10,
      paddingVertical: 5,
      alignSelf: 'flex-start',
      backgroundColor: colors.other.chatBubble,
    },
    message: {
      color: 'black',
      padding: 10,
      paddingTop: 5,
      fontFamily: 'avenir_roman',
      fontSize: 16,
    },
    infoStyle: {
      color: 'black',
      padding: 10,
      paddingBottom: 0,
      fontSize: 12,
      fontFamily: 'avenir_light',
    },
  },
  right: {
    container: {
      borderRadius: 20,
      borderBottomRightRadius: 0,
      marginTop: 8,
      marginRight: 10,
      marginLeft: 150,
      paddingHorizontal: 10,
      paddingVertical: 5,
      alignSelf: 'flex-end',
      backgroundColor: colors.secondary.blue,
    },
    message: {
      color: 'white',
      padding: 10,
      paddingTop: 5,
      fontFamily: 'avenir_roman',
      fontSize: 16,
    },
    infoStyle: {
      color: 'white',
      padding: 10,
      paddingBottom: 0,
      fontSize: 12,
      fontFamily: 'avenir_light',
    },
  },
  topContainerStyle: {
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
};

export { ChatBubble };

我应该得到的行为

我目前收到的行为

标签: javascriptreact-nativereact-native-flatlist

解决方案


从您在问题中提到的代码来看,问题似乎是在追加新元素时状态不保持先前的数组元素。

const messages = [...this.state.messages,messageData] //

考虑this.state.messages为数组持有supposed data并与messageData数组的单个元素相同。

this.setState({ messages:messages  });

推荐阅读