【问题标题】:React Native ListView renderRow method not firing with proper dataSourceReact Native ListView renderRow 方法未使用正确的数据源触发
【发布时间】:2017-06-27 18:27:01
【问题描述】:

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

问题

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

状态中的 dataSource 对象更新得很好,我可以进行行计数并查看它是否正确更新。我还可以查看传入数组中的最后一个对象,并查看我刚刚添加的当前消息以及正确的文本和日期。但是,当单步执行 renderMessageRow 函数时,我可以看到每一行都呈现 EXCEPT 新行。 WTF ...当我在此行渲染函数中暂停或打印时,参数仅在新消息之前的对象处停止。然而,当我从renderMessageRow 方法内部打印出this.state.dataSource 时,真正的乐趣就开始了。当你这样做时,新的信息就在那里!!我可以看到它,并且行数显示它在 dataSource 对象中增加了 1。哈哈

我已经尝试以多种方式更改此实现,添加大量切片或扩展运算符以确保进入的数组与更改之前的状态不同。没有任何工作。更奇怪的是,在我将来自 REDUX 的数据源从对象对象(无法保持顺序)更改为对象数组之前,此操作运行良好。当它是对象的对象时,新消息总是出现在整个列表中的随机位置...

守则

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),
            });
        }
    }


}

【问题讨论】:

    标签: arrays listview react-native redux datasource


    【解决方案1】:

    我现在已经通过添加initialListSize 属性解决了这个问题。我无法想象这是永久的解决方案,但是由于没有其他人回应我正在为谷歌搜索者回答这个问题。如果其他人给出更好的答案,我将删除它并给他们学分。

    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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-25
      • 2017-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-23
      • 2017-10-20
      • 1970-01-01
      相关资源
      最近更新 更多