import React from 'react'; import { ActivityIndicator, FlatList } from 'react-native'; import PropTypes from 'prop-types'; import { responsive } from 'react-native-responsive-ui'; import styles from './styles'; import database, { safeAddListener } from '../../lib/realm'; import scrollPersistTaps from '../../utils/scrollPersistTaps'; import debounce from '../../utils/debounce'; import RocketChat from '../../lib/rocketchat'; import log from '../../utils/log'; import EmptyRoom from './EmptyRoom'; import ScrollBottomButton from './ScrollBottomButton'; import { isNotch } from '../../utils/deviceInfo'; @responsive export class List extends React.Component { static propTypes = { onEndReached: PropTypes.func, renderFooter: PropTypes.func, renderRow: PropTypes.func, room: PropTypes.object, window: PropTypes.object }; constructor(props) { super(props); this.data = database .objects('messages') .filtered('rid = $0', props.room.rid) .sorted('ts', true); this.state = { loading: true, loadingMore: false, end: false, messages: this.data.slice(), showScollToBottomButton: false }; safeAddListener(this.data, this.updateState); } // shouldComponentUpdate(nextProps, nextState) { // const { // loadingMore, loading, end, showScollToBottomButton, messages // } = this.state; // const { window } = this.props; // return end !== nextState.end // || loadingMore !== nextState.loadingMore // || loading !== nextState.loading // || showScollToBottomButton !== nextState.showScollToBottomButton // // || messages.length !== nextState.messages.length // || !equal(messages, nextState.messages) // || window.width !== nextProps.window.width; // } componentWillUnmount() { this.data.removeAllListeners(); this.updateState.stop(); } // eslint-disable-next-line react/sort-comp updateState = debounce(() => { this.setState({ messages: this.data.slice(), loading: false, loadingMore: false }); }, 300); onEndReached = async() => { const { loadingMore, loading, end, messages } = this.state; if (loadingMore || loading || end || messages.length < 50) { return; } this.setState({ loadingMore: true }); const { room } = this.props; try { const result = await RocketChat.loadMessagesForRoom({ rid: room.rid, t: room.t, latest: this.data[this.data.length - 1].ts }); this.setState({ end: result.length < 50 }); } catch (e) { this.setState({ loadingMore: false }); log('ListView.onEndReached', e); } } scrollToBottom = () => { requestAnimationFrame(() => { this.list.scrollToOffset({ offset: isNotch ? -90 : -60 }); }); } handleScroll = (event) => { if (event.nativeEvent.contentOffset.y > 0) { this.setState({ showScollToBottomButton: true }); } else { this.setState({ showScollToBottomButton: false }); } } renderFooter = () => { const { loadingMore, loading } = this.state; if (loadingMore || loading) { return ; } return null; } render() { const { renderRow, window } = this.props; const { showScollToBottomButton, messages } = this.state; return ( this.list = ref} keyExtractor={item => item._id} data={messages} extraData={this.state} renderItem={({ item, index }) => renderRow(item, messages[index + 1])} contentContainerStyle={styles.contentContainer} style={styles.list} onScroll={this.handleScroll} inverted removeClippedSubviews initialNumToRender={10} onEndReached={this.onEndReached} onEndReachedThreshold={0.5} maxToRenderPerBatch={20} ListFooterComponent={this.renderFooter} {...scrollPersistTaps} /> window.height} /> ); } }