React-redux无限重新安装组件

时间:2017-09-15 10:29:03

标签: reactjs redux react-redux

我是react / redux的初学者,我遇到了一个奇怪的应用程序行为 每次尝试调度动作,例如

store.dispatch({type: 'no_matter_what_is_here'});
即使商店的状态没有反复改变,也可以重新安装所有组件,并提供无限的组件呈现(组件使用' connect'功能来自' react-redux'库)。

我使用这些库:

"dependencies": {
"babel-polyfill": "^6.3.14",
"bluebird": "^3.4.1",
"eventsource-polyfill": "^0.9.6",
"font-awesome-webpack": "0.0.4",
"history": "^4.7.2",
"lodash": "^4.17.4",
"material-ui": "^0.19.1",
"moment": "^2.13.0",
"prop-types": "^15.5.10",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-dropzone": "^3.5.1",
"react-modal": "^1.4.0",
"react-redux": "^5.0.2",
"react-router": "^3.0.0",
"react-router-dom": "^4.2.2",
"react-router-redux": "^4.0.6",
"react-scripts": "1.0.13",
"react-tap-event-plugin": "^2.0.1",
"redux": "^3.6.0",
"superagent": "^3.1.0",
"uuid": "^3.0.1"
},

这种行为的原因是什么?

示例代码组件(但它关注应用程序中的每个组件)

import React, { Component } from 'react';
import store from '../../store';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import _ from 'lodash';
import { CircularProgress } from 'material-ui';
import debounce from '../../modules/debounce';
import { JobAddDialog } from '../job';
import WorkdeckPanel from './workdeckPanel';
import QueuedJobList from './queuedJobList';
import { Label, WarningDialog, InfoDialog } from '../controls';
import { setupActions, jobActions } from '../../actions';
import {
  connectTask,
  reConnectTask,
  cancelTask,
  loadStatus,
  startTask,
  pauseTask,
  stopTask,
  skipTask,
  retryTask,
} from '../../actions/printerActions';
import { getEnumName } from '../../modules/enumHelpers';
import { printerErrorTypeEnum, printerStatusEnum } from '../../constants';

class Status extends Component {
  static get propTypes() {
    return {
      printer: PropTypes.shape({
        status: PropTypes.number.isRequired,
      }),
      jobs: PropTypes.shape({
        list: PropTypes.array.isRequired,
      }).isRequired,
      resources: PropTypes.shape({}).isRequired,
    };
  }

  static get defaultProps() {
    return {
      printer: {},
      jobs: {
        list: [],
      },
    };
  }

  constructor(props) {
    super(props);
    this.state = {
      showAddDialog: false,
      showConfirm: false,
      showStop: false,
      selectedJobId: null,
    };
    this.onJobSelected = this.onJobSelected.bind(this);
    this.onStatusLoaded = this.onStatusLoaded.bind(this);
  }

  componentWillMount() {
    store.dispatch({type: 'no_matter_what'});
  }

  componentDidUpdate() {
    const { printer } = this.props;
    const { showAddDialog } = this.state;
    const { isLoading, status } = (printer || {});
    if (!isLoading && !showAddDialog
      && [printerStatusEnum.notResponding, printerStatusEnum.confirming, printerStatusEnum.suspended].indexOf(status) === -1) {
      debounce(this.onStatusLoaded, 1000);
    }
  }

  onStatusLoaded() {
    const { jobs, printer } = this.props;
    loadStatus(printer.updateDate)
      .then((res) => {
        const job = Object.assign({ id: -1 }, printer.job);
        const newJob = res.job ? _.find(jobs.list, { id: res.job.id }) : { id: -1 };
        if (newJob.id !== job.id) {
          return jobActions.loadJobs();
        }
        return null;
      });
  }

  onJobSelected(selectedJobId) {
    this.setState({ selectedJobId });
  }

  render() {
    const { jobs, printer, resources } = this.props;
    const { selectedJobId, showAddDialog, showConfirm, showStop } = this.state;
    return (
      <div className="statusContainer">
        <QueuedJobList {...{
          jobs, selectedJobId, onJobSelect: this.onJobSelected, onJobAdd: () => { this.setState({ showAddDialog: true }); },
        }}
        />
        <WorkdeckPanel {...{ jobs,
          printer,
          selectedJobId,
          resources,
          onStartClick: () => {
            if (printer.job && printer.status === printerStatusEnum.suspended) {
              this.setState({ showConfirm: true });
            } else {
              startTask();
            }
          },
          onStopClick: () => { this.setState({ showStop: true }); },
        }}
        />

        { [printerStatusEnum.initializing].indexOf(printer.status) !== -1
          ? (<InfoDialog {...{
            title: resources.get('device.connecting.title'),
            show: true,
            onCancel: cancelTask }}
          >
            <div className="iconProgress"><CircularProgress thickness={5} /></div>
            <h3 className="textAlert">
              <Label path="device.connecting.note" />
            </h3>
          </InfoDialog>)
          : null }
        <JobAddDialog {...{
          show: showAddDialog,
          isQueued: true,
          onClose: () => { this.setState({ showAddDialog: false }); },
        }}
        />
        <ConfirmDialog {...{ printer, showConfirm, onHide: () => { this.setState({ showConfirm: false }); }, resources }} />
        <NotRespondingDialog {...this.props} />
        <ErrorDialog {...{ showStop, onCancel: () => { this.setState({ showStop: true }); }, printer, resources }} />
        <StopDialog {...{ show: showStop, onClose: () => { this.setState({ showStop: false }); }, resources }} />
      </div>
    );
  }
}

const ConfirmDialog = ({ printer, showConfirm, onHide, resources }) => {
  const { status, method } = printer;
  let onCancel = onHide;
  let show = showConfirm;
  if (status === printerStatusEnum.confirming) {
    onCancel = () => {
      onHide();
      cancelTask();
    };
    show = true;
  }
  if (show) {
    return (
      <InfoDialog {...{
        title: resources.get('device.confirming.title'),
        okCaption: resources.get('buttons.continue'),
        show,
        onCancel,
        onOk: () => {
          onHide();
          startTask();
        },
      }}
      >
        <Label {...{ path: 'device.confirming.note', replacements: method }} />
      </InfoDialog>);
  }
  return null;
};

const NotRespondingDialog = (props) => {
  const { resources, printer } = props;
  if (printer.status === printerStatusEnum.notResponding) {
    return (
      <WarningDialog {...{
        title: resources.get('device.notResponding.title'),
        okCaption: resources.get('buttons.retry'),
        show: true,
        buttons: [
          { type: 'Cancel', onClick: cancelTask },
          { type: 'Retry', onClick: reConnectTask, isPrimary: true },
        ] }}
      >
        <Label path="device.notResponding.note" />
      </WarningDialog>);
  }
  return null;
};

const ErrorDialog = ({ showStop, onCancel, printer, resources }) => {
  const { status, errorType } = printer;
  if (status === printerStatusEnum.inError && !showStop) {
    const error = getEnumName(printerErrorTypeEnum, errorType);
    let buttons = [
      { type: 'Ok', onClick: pauseTask, isPrimary: true },
    ];
    if (errorType === printerErrorTypeEnum.tubeError) {
      buttons = [
        { type: 'Cancel', onClick: onCancel },
        { type: 'Skip', onClick: skipTask },
        { type: 'Retry', onClick: retryTask, isPrimary: true },
      ];
    }
    return (
      <WarningDialog {...{
        title: resources.get(`device.${error}.title`),
        show: true,
        buttons }}
      >
        <Label {...{ path: `device.${error}.note` }} />
      </WarningDialog>);
  }
  return null;
};

const StopDialog = ({ show, onClose, resources }) => {
  if (show) {
    return (
      <WarningDialog {...{
        title: resources.get('device.stopping.title'),
        show: true,
        buttons: [
          { type: 'Cancel', onClick: onClose },
          { type: 'Ok', onClick: () => { stopTask().then(() => { onClose(); }); }, isPrimary: true },
        ] }}
      >
        <Label className="textInfo" path="device.stopping.note" />
      </WarningDialog>);
  }
  return null;
};

export default connect(
  state => ({
    jobs: state.jobs,
    printer: state.printer,
    resources: state.resources,
  }),
)(Status);

2 个答案:

答案 0 :(得分:1)

首先,您应该将此代码拆分为Presentational Componentes和Containers。容器保持逻辑和与您的商店的连接。这将使您的代码不易出错,更容易阅读。

关于您的问题,您可以store.dispatch({type: 'no_matter_what'});componentWillMount发送此邮件。这不是一个好习惯,因为你可以阅读here。我建议你从那里删除它。

另外,我会研究那里的那些绑定。试着了解你是否真的需要它们,因为它们是atm。我没有足够的知识,但我会查看this文章,这篇文章非常好(虽然不完美)。

在这种情况下,我建议您使用箭头功能,并确保需要此onStatusLoaded绑定。你在构造函数中绑定它,在onStatusLoaded里面,你似乎每次更新组件时都会再次更新状态,这将导致一个循环。

答案 1 :(得分:0)

您的错误可能在componentDidUpdate方法中,您需要在条件中控制每个步骤以捕获永久重新校正: enter image description here