Fix updates being hidden behind pending items on unmounted components (#11898)
This commit is contained in:
		
							parent
							
								
									a90243a712
								
							
						
					
					
						commit
						ba0de8fb68
					
				
					 4 changed files with 33 additions and 4 deletions
				
			
		| 
						 | 
					@ -28,6 +28,9 @@ export const NOTIFICATIONS_CLEAR        = 'NOTIFICATIONS_CLEAR';
 | 
				
			||||||
export const NOTIFICATIONS_SCROLL_TOP   = 'NOTIFICATIONS_SCROLL_TOP';
 | 
					export const NOTIFICATIONS_SCROLL_TOP   = 'NOTIFICATIONS_SCROLL_TOP';
 | 
				
			||||||
export const NOTIFICATIONS_LOAD_PENDING = 'NOTIFICATIONS_LOAD_PENDING';
 | 
					export const NOTIFICATIONS_LOAD_PENDING = 'NOTIFICATIONS_LOAD_PENDING';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const NOTIFICATIONS_MOUNT   = 'NOTIFICATIONS_MOUNT';
 | 
				
			||||||
 | 
					export const NOTIFICATIONS_UNMOUNT = 'NOTIFICATIONS_UNMOUNT';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineMessages({
 | 
					defineMessages({
 | 
				
			||||||
  mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
 | 
					  mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
 | 
				
			||||||
  group: { id: 'notifications.group', defaultMessage: '{count} notifications' },
 | 
					  group: { id: 'notifications.group', defaultMessage: '{count} notifications' },
 | 
				
			||||||
| 
						 | 
					@ -215,3 +218,11 @@ export function setFilter (filterType) {
 | 
				
			||||||
    dispatch(saveSettings());
 | 
					    dispatch(saveSettings());
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const mountNotifications = () => ({
 | 
				
			||||||
 | 
					  type: NOTIFICATIONS_MOUNT,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const unmountNotifications = () => ({
 | 
				
			||||||
 | 
					  type: NOTIFICATIONS_UNMOUNT,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -199,7 +199,12 @@ export default class ScrollableList extends PureComponent {
 | 
				
			||||||
    this.clearMouseIdleTimer();
 | 
					    this.clearMouseIdleTimer();
 | 
				
			||||||
    this.detachScrollListener();
 | 
					    this.detachScrollListener();
 | 
				
			||||||
    this.detachIntersectionObserver();
 | 
					    this.detachIntersectionObserver();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    detachFullscreenListener(this.onFullScreenChange);
 | 
					    detachFullscreenListener(this.onFullScreenChange);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (this.props.onScrollToTop) {
 | 
				
			||||||
 | 
					      this.props.onScrollToTop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onFullScreenChange = () => {
 | 
					  onFullScreenChange = () => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import Column from '../../components/column';
 | 
					import Column from '../../components/column';
 | 
				
			||||||
import ColumnHeader from '../../components/column_header';
 | 
					import ColumnHeader from '../../components/column_header';
 | 
				
			||||||
import { expandNotifications, scrollTopNotifications, loadPending } from '../../actions/notifications';
 | 
					import { expandNotifications, scrollTopNotifications, loadPending, mountNotifications, unmountNotifications } from '../../actions/notifications';
 | 
				
			||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
 | 
					import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
 | 
				
			||||||
import NotificationContainer from './containers/notification_container';
 | 
					import NotificationContainer from './containers/notification_container';
 | 
				
			||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
					import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
				
			||||||
| 
						 | 
					@ -66,11 +66,16 @@ class Notifications extends React.PureComponent {
 | 
				
			||||||
    trackScroll: true,
 | 
					    trackScroll: true,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  componentWillMount() {
 | 
				
			||||||
 | 
					    this.props.dispatch(mountNotifications());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentWillUnmount () {
 | 
					  componentWillUnmount () {
 | 
				
			||||||
    this.handleLoadOlder.cancel();
 | 
					    this.handleLoadOlder.cancel();
 | 
				
			||||||
    this.handleScrollToTop.cancel();
 | 
					    this.handleScrollToTop.cancel();
 | 
				
			||||||
    this.handleScroll.cancel();
 | 
					    this.handleScroll.cancel();
 | 
				
			||||||
    this.props.dispatch(scrollTopNotifications(false));
 | 
					    this.props.dispatch(scrollTopNotifications(false));
 | 
				
			||||||
 | 
					    this.props.dispatch(unmountNotifications());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleLoadGap = (maxId) => {
 | 
					  handleLoadGap = (maxId) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,8 @@ import {
 | 
				
			||||||
  NOTIFICATIONS_CLEAR,
 | 
					  NOTIFICATIONS_CLEAR,
 | 
				
			||||||
  NOTIFICATIONS_SCROLL_TOP,
 | 
					  NOTIFICATIONS_SCROLL_TOP,
 | 
				
			||||||
  NOTIFICATIONS_LOAD_PENDING,
 | 
					  NOTIFICATIONS_LOAD_PENDING,
 | 
				
			||||||
 | 
					  NOTIFICATIONS_MOUNT,
 | 
				
			||||||
 | 
					  NOTIFICATIONS_UNMOUNT,
 | 
				
			||||||
} from '../actions/notifications';
 | 
					} from '../actions/notifications';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  ACCOUNT_BLOCK_SUCCESS,
 | 
					  ACCOUNT_BLOCK_SUCCESS,
 | 
				
			||||||
| 
						 | 
					@ -22,6 +24,7 @@ const initialState = ImmutableMap({
 | 
				
			||||||
  items: ImmutableList(),
 | 
					  items: ImmutableList(),
 | 
				
			||||||
  hasMore: true,
 | 
					  hasMore: true,
 | 
				
			||||||
  top: false,
 | 
					  top: false,
 | 
				
			||||||
 | 
					  mounted: false,
 | 
				
			||||||
  unread: 0,
 | 
					  unread: 0,
 | 
				
			||||||
  isLoading: false,
 | 
					  isLoading: false,
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					@ -35,9 +38,10 @@ const notificationToMap = notification => ImmutableMap({
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const normalizeNotification = (state, notification, usePendingItems) => {
 | 
					const normalizeNotification = (state, notification, usePendingItems) => {
 | 
				
			||||||
  const top = state.get('top');
 | 
					  const top     = state.get('top');
 | 
				
			||||||
 | 
					  const mounted = state.get('mounted');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (usePendingItems || !top || !state.get('pendingItems').isEmpty()) {
 | 
					  if (usePendingItems || (!top && mounted) || !state.get('pendingItems').isEmpty()) {
 | 
				
			||||||
    return state.update('pendingItems', list => list.unshift(notificationToMap(notification))).update('unread', unread => unread + 1);
 | 
					    return state.update('pendingItems', list => list.unshift(notificationToMap(notification))).update('unread', unread => unread + 1);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,7 +67,7 @@ const expandNormalizedNotifications = (state, notifications, next, isLoadingRece
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return state.withMutations(mutable => {
 | 
					  return state.withMutations(mutable => {
 | 
				
			||||||
    if (!items.isEmpty()) {
 | 
					    if (!items.isEmpty()) {
 | 
				
			||||||
      usePendingItems = isLoadingRecent && (usePendingItems || !mutable.get('top') || !mutable.get('pendingItems').isEmpty());
 | 
					      usePendingItems = isLoadingRecent && (usePendingItems || (!mutable.get('top') && mutable.get('mounted')) || !mutable.get('pendingItems').isEmpty());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      mutable.update(usePendingItems ? 'pendingItems' : 'items', list => {
 | 
					      mutable.update(usePendingItems ? 'pendingItems' : 'items', list => {
 | 
				
			||||||
        const lastIndex = 1 + list.findLastIndex(
 | 
					        const lastIndex = 1 + list.findLastIndex(
 | 
				
			||||||
| 
						 | 
					@ -134,6 +138,10 @@ export default function notifications(state = initialState, action) {
 | 
				
			||||||
    return action.timeline === 'home' ?
 | 
					    return action.timeline === 'home' ?
 | 
				
			||||||
      state.update(action.usePendingItems ? 'pendingItems' : 'items', items => items.first() ? items.unshift(null) : items) :
 | 
					      state.update(action.usePendingItems ? 'pendingItems' : 'items', items => items.first() ? items.unshift(null) : items) :
 | 
				
			||||||
      state;
 | 
					      state;
 | 
				
			||||||
 | 
					  case NOTIFICATIONS_MOUNT:
 | 
				
			||||||
 | 
					    return state.set('mounted', true);
 | 
				
			||||||
 | 
					  case NOTIFICATIONS_UNMOUNT:
 | 
				
			||||||
 | 
					    return state.set('mounted', false);
 | 
				
			||||||
  default:
 | 
					  default:
 | 
				
			||||||
    return state;
 | 
					    return state;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue