React Native ListView renderRow方法没有使用正确的dataSource

时间:2017-06-27 18:27:01

标签: arrays listview react-native redux datasource

我一直在使用React Native已经有一段时间了,之前我从未遇到过这个问题。也许是因为通常我的数据对象实际上是一个对象,而目前它是一个对象数组。至关重要的是它仍然是一个数组,以便我可以保持正确的顺序。这是一个信使应用程序,所以一旦我按日期排序了消息,我需要它保持这种方式。

问题

对话中的新消息将呈现!我使用REDUX / Firebase与我的远程数据库同步,当我通过应用程序发送消息时,我正在侦听新消息,然后更新状态。我没有使用child_appended事件而是使用value事件,因为我希望整个收件箱中的邮件都有变化。所有这一切都正确发生,没有错误。

状态更新的dataSource对象就好了,我可以进行行计数并看到它正确更新。我还可以查看传入数组中的最后一个对象,并查看刚刚添加了正确文本和日期的当前消息。但是,当单步执行renderMessageRow函数时,我可以看到每一行都呈现 EXCEPT 新行。 WTF ...当我在此行渲染功能中暂停或打印时,参数只会停留在新消息之前的对象上。但是,当我从this.state.dataSource方法中打印renderMessageRow时,真正的乐趣开始了。当你这样做时,新消息就在那里!我可以看到它,行数显示它在dataSource对象中增加了一个。大声笑

我已经尝试过多种方式更改此实现,添加大量切片或扩展运算符以确保它不像以前在更改之前的状态那样进入。什么都行不通。更奇怪的是,在将REDUX中的dataSource从对象对象(无法维护顺序)更改为对象数组之前,此操作正常工作。当它是对象的对象时,新消息总是出现在整个列表中的随机位置......

守则

export default class SingleConvoView extends Component {

    //rN Lifecycle ----------------------

    constructor(props) {
        super(props);

        this.dataProtocol = new ListView.DataSource({
            rowHasChanged: (row1, row2) => row1 !== row2,
        });

        this.state = {
            conversationListViewHeight: 0,
            dataSource: this.dataProtocol.cloneWithRows(this.props.messages),
        };
    }


    componentWillReceiveProps(nextProps, nextState) {
        if(deepEqual(this.props.messages, nextProps.messages, {strict: true}) === false) {
            //This fires every time the REDUX state changes without any problems at all
            //The messages property here has the new message appended to it
            //The row count shows 1 more showing than before sending the message
            this.updateDataSource(nextProps.messages);
        }
    }


    componentDidReceiveProps(nextProps, nextState) {
        //Tried this just incase, didn't work, commented out...
        //this.state.dataSource.rowShouldUpdate('s1', (nextProps.messages.length - 1));
    }


    render() {
        return (
            <View style={[
                styles.container,
                {
                    width: this.props.display.width,
                    height: this.props.display.height,
                }
            ]}>

                { this.renderConversation() }
            </View>
        );
    }


    renderConversation() {
        if(this.state.dataSource.getRowCount() > 0) {
            return (
                <View style={{ height: (this.props.display.height - headerBarHeight - 50) }}>
                    <ListView
                        onLayout={event => {
                            // console.log('on layout event: new content size is: ', event.nativeEvent.layout.height);
                            this.setState({ conversationListViewHeight: event.nativeEvent.layout.height });
                        }}
                        onContentSizeChange={(newWidth, newHeight) => {
                            let totalContentHeight = newHeight - this.state.conversationListViewHeight + headerBarHeight;

                            if(this.state.conversationListViewHeight === 0 || newHeight < this.state.conversationListViewHeight) totalContentHeight = 0;
                            this.conversationScrollViewRef.scrollTo({ x: 0, y: totalContentHeight, animated: false });
                        }}
                        scrollEnabled={true}
                        removeClippedSubviews={false}
                        dataSource={this.state.dataSource}
                        renderRow={this.renderMessageRow.bind(this)}
                        pageSize={this.state.dataSource.getRowCount()}
                        ref={ref => { this.conversationScrollViewRef = ref; }}
                        renderScrollComponent={this.renderScrollComponent.bind(this)} />
                </View>
            );

        } else {
            return null;
        }
    }


    renderScrollComponent(props) {
        return (
            <ScrollView 
                contentContainerStyle={{ paddingBottom: 20 }}
                style={[
                    styles.conversationBox,
                    { width: this.props.display.width - mainContainerSideMargins }
                ]} />
        );
    }


    renderMessageRow(message, sectionID, rowID, highlightRow) {
        let messageUser = message.userMessage ? 'You' : (this.props.senderFirstName || 'no name'),
            messageTime = '', messageTitle = '';

        if(message.hasOwnProperty('created')) {
            let currentSentDate = new Date(message.created);
            messageTime = `${currentSentDate.toLocaleDateString('en-US', DATE_DISPLAY_OPTIONS)}`;
        }

        messageTitle = message.userMessage ? `${messageTime}: ${messageUser}` : `${messageUser}: ${messageTime}`;

        return (
            <View style={styles.messageRow}>
                <Text style={[
                        bodyFontStyle, 
                        styles.messageOwnerHeader,
                        { 
                            color: message.userMessage ? brand_blue_color : primary_color,
                            alignSelf: message.userMessage ? 'flex-end' : 'flex-start',
                        }
                    ]}>

                    { messageTitle }
                </Text>

                <View 
                    shadowRadius={2}
                    shadowOpacity={1}
                    shadowColor={'rgba(0, 0, 0, 0.4)'}
                    shadowOffset={{width: -1, height: 1}}
                    style={styles.messageBodyContainer}>

                    <Text style={[
                            styles.messageBody,
                            { textAlign: message.userMessage ? 'right' : 'left' }
                        ]}>

                        { message.body }
                    </Text>
                </View>
            </View>
        );
    }


    //Functionality ---------------------

    updateDataSource(data) {
        if(typeof data != 'undefined' || data != null) {
            let tempData = data.slice();

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


}

1 个答案:

答案 0 :(得分:0)

我现在通过添加initialListSize道具解决了这个问题。我无法想象这是永久的解决方案,但是因为没有其他人做出回应我正在为Google搜索者回答这个问题。如果其他人给出了更好的答案,我会将其删除并给予他们学分。

renderConversation() {
    if(this.state.dataSource.getRowCount() > 0) {
        return (
            <View style={{ height: (this.props.display.height - headerBarHeight - 50) }}>
                <ListView
                    onLayout={event => {
                        this.setState({ conversationListViewHeight: event.nativeEvent.layout.height });
                    }}
                    onContentSizeChange={(newWidth, newHeight) => {
                        let totalContentHeight = newHeight - this.state.conversationListViewHeight + headerBarHeight;

                        if(this.state.conversationListViewHeight === 0 || newHeight < this.state.conversationListViewHeight) totalContentHeight = 0;
                        this.conversationScrollViewRef.scrollTo({ x: 0, y: totalContentHeight, animated: false });
                    }}
                    initialListSize={this.state.dataSource.getRowCount()}
                    scrollEnabled={true}
                    removeClippedSubviews={false}
                    dataSource={this.state.dataSource}
                    renderRow={this.renderMessageRow.bind(this)}
                    pageSize={this.state.dataSource.getRowCount()}
                    ref={ref => { this.conversationScrollViewRef = ref; }}
                    renderScrollComponent={this.renderScrollComponent.bind(this)} />
            </View>
        );

    } else {
        return null;
    }
}