我是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);
答案 0 :(得分:1)
首先,您应该将此代码拆分为Presentational Componentes和Containers。容器保持逻辑和与您的商店的连接。这将使您的代码不易出错,更容易阅读。
关于您的问题,您可以store.dispatch({type: 'no_matter_what'});
在componentWillMount
发送此邮件。这不是一个好习惯,因为你可以阅读here。我建议你从那里删除它。
另外,我会研究那里的那些绑定。试着了解你是否真的需要它们,因为它们是atm。我没有足够的知识,但我会查看this文章,这篇文章非常好(虽然不完美)。
在这种情况下,我建议您使用箭头功能,并确保需要此onStatusLoaded
绑定。你在构造函数中绑定它,在onStatusLoaded
里面,你似乎每次更新组件时都会再次更新状态,这将导致一个循环。
答案 1 :(得分:0)