仅在Redux中没有本地状态时才发出通知吗?

时间:2019-06-12 07:08:09

标签: javascript reactjs redux

我在react-redux应用程序中使用通知系统Notify。最近,我在代码中收到有关该问题的信息。这段代码可以正常工作,但是有人告诉我可以通过仅在redux中存储通知来简化代码。我不太了解这一点,这就是为什么我将在本文中显示整个代码。

我收到有关此问题的通知: 我认为通知应该只保存在Redux中,现在它们随Redux一起保存,然后保存到本地状态。这可以简化。

这是我的Notifier.js component,我必须将其导入要在其中显示通知的容器:

import { Component } from 'react';
import { makeNotificationsSelector } from 'containers/App/selectors';
import {
  removeSnackbarAction,
  closeSnackbarAction,
} from 'containers/App/actions';
import PropTypes from 'prop-types';
import { withSnackbar } from 'notistack';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { compose } from 'redux';

class Notifier extends Component {
  displayed = [];

  storeDisplayed = id => {
    this.displayed = [...this.displayed, id];
  };

  shouldComponentUpdate({ notifications, onCloseSnackbar, onRemoveSnackbar }) {
    if (!notifications.length) {
      this.displayed = [];
      return false;
    }

    const { notifications: currentSnacks } = this.props;
    let notExists = false;

    for (let i = 0; i < notifications.length; i += 1) {
      const newSnack = notifications[i];

      if (newSnack.dismissed) {
        onCloseSnackbar(newSnack.key);
        onRemoveSnackbar(newSnack.key);
      }

      if (!notExists) {
        notExists =
          notExists ||
          !currentSnacks.filter(({ key }) => newSnack.key === key).length;
      }
    }

    return notExists;
  }

  componentDidUpdate({ onRemoveSnackbar }) {
    const { notifications = [] } = this.props;

    notifications.forEach(({ key, message, options = {} }) => {
      if (this.displayed.includes(key)) return;

      this.props.enqueueSnackbar(message, {
        ...options,
        onClose: (event, reason, id) => {
          if (options.onClose) {
            options.onClose(event, reason, id);
          }
          onRemoveSnackbar(id);
        },
      });

      this.storeDisplayed(key);
    });
  }

  render() {
    return null;
  }
}

Notifier.propTypes = {
  notifications: PropTypes.array,
  enqueueSnackbar: PropTypes.func,
  onRemoveSnackbar: PropTypes.func,
  onCloseSnackbar: PropTypes.func,
};

const mapStateToProps = createStructuredSelector({
  notifications: makeNotificationsSelector(),
});

function mapDispatchToProps(dispatch) {
  return {
    onRemoveSnackbar: key => dispatch(removeSnackbarAction(key)),
    onCloseSnackbar: key => dispatch(closeSnackbarAction(key)),
  };
}

const withConnect = connect(
  mapStateToProps,
  mapDispatchToProps,
);

export default compose(
  withSnackbar,
  withConnect,
)(Notifier);

这是我的Redux actions.js

import {
  ENQUEUE_SNACKBAR,
  CLOSE_SNACKBAR,
  REMOVE_SNACKBAR,
} from './constants';

export function enqueueSnackbarAction(notification) {
  const key = notification.options && notification.options.key;

  return {
    type: ENQUEUE_SNACKBAR,
    notification: {
      ...notification,
      key: key || new Date().getTime() + Math.random(),
    },
  };
}

export function closeSnackbarAction(key) {
  return {
    type: CLOSE_SNACKBAR,
    dismissAll: !key,
    key,
  };
}

export function removeSnackbarAction(key) {
  return {
    type: REMOVE_SNACKBAR,
    key,
  };
}

这是我的Redux reducer.js

import produce from 'immer';
import {
  ENQUEUE_SNACKBAR,
  CLOSE_SNACKBAR,
  REMOVE_SNACKBAR,
} from './constants';

export const initialState = {
  notifications: [],
};

const loginPageReducer = (state = initialState, action) =>
  produce(state, draft => {
    switch (action.type) {
      case ENQUEUE_SNACKBAR:
        draft.notifications = [
          ...draft.notifications,
          {
            key: action.key,
            ...action.notification,
          },
        ];
        break;
      case CLOSE_SNACKBAR:
        draft.notifications = draft.notifications.map(notification =>
          action.dismissAll || notification.key === action.key
            ? { ...notification, dismissed: true }
            : { ...notification },
        );
        break;
      case REMOVE_SNACKBAR:
        draft.notifications = draft.notifications.filter(
          notification => notification.key !== action.key,
        );
        break;
    }
  });

export default loginPageReducer;

...然后我用redux-saga进行通知:

export function* makeNotification() {
    yield put(
      enqueueSnackbarAction({
        message: 'Failed fetching data.',
        options: {
          key: new Date().getTime() + Math.random(),
          variant: 'warning',
          autoHideDuration: 3000,
        },
      }),
    );
}

0 个答案:

没有答案