我正在使用React-Redux 5.0.6,并具有以下代码的还原器:
export default (state = [], action) => {
switch(action.type) {
case 'ADD_ENGAGEMENT':
let newArr = state.slice();
newArr.push(action.payload);
return newArr;
case 'UPDATE_ENGAGEMENT':
console.info('UPDATE_ENGAGEMENT')
return state.slice();
// return state;
default:
return state;
}}
问题发生在" update_engagement"案例中 - 实际逻辑已被删除并用最简单的示例代替以证明问题。
当返回从状态创建的新数组时,返回了循环(触发循环),导致派遣操作,直到"未熟悉的刻录器:最大呼叫堆栈大小超过超过"错误。问题出现期间浏览器控制台的屏幕截图
问题不仅限于" slice()",并且每当包含任何状态元素的数组返回,例如返回[state [0]]。返回原始状态时,不会发生问题。我对这种行为感到困惑,无法理解我的应用程序中的任何内容可能导致它。任何洞察力都将不胜感激。
提供一些其他上下文,以下是派遣操作中涉及的代码:
componentWillReceiveProps(newProps) {
let engagementTemplateData = newProps.selectedEngagementTemplate;
let engagements = newProps.engagements;
if (engagementTemplateData && engagementTemplateData.engagementUuid === this.props.uuid) {
let template = engagementTemplateData.template;
this.updateEngagementTemplate(template);
}
}
updateEngagementTemplate(template) {
let url = `/engagements/${this.props.uuid}`;
let requestHelper = new AjaxRequestHelper(url);
let data = {template_uuid: template.uuid};
this.props.updateEngagement({uuid: this.props.uuid, template: template});
// requestHelper.put(data, response => {
// this.props.updateEngagement({uuid: this.props.uuid, template: template});
// });
}
基本上,触发该动作的函数是在组成的WillReceiveProps中称为另一个动作的。但是,我不确定这些信息有多有用,因为降低器本身在响应该动作时似乎在正常工作 - 这只是状态正在发生的奇怪的事情,这阻止了其元素被返回。
从它的声音(以及从react callstack)中,我想像商店中的数组更改(通过引用)是由React组件道具拾取的,这应该在其中/DID UPDATE LOGIC在没有警卫的情况下调用该操作。从componentDidMount/Update
调用操作或setState
时,这通常是一个错误 -
当返回原始状态时,它起作用,因为引用是相同的,因此React不会继续其更新逻辑,因此调用您的代码发布该操作
考虑将使用您的还原代码引起无尽环路的纯组件...
export interface IMyProps {
myArray: any[],
updateEngagementAction: () => void
}
export class EndlessLoopFromArrayPropComponent extends React.PureComponent<IMyProps> {
// PureComponent compares props by reference only
// so will cause update if this.props.myArray reference has changed in store (ie from slice())
render() {
// blahblah...
}
componentDidUpdate() {
// this will call action after every update
// as every time this action is called it passes in a new reference this.props.myArray to this component
// so react will update this component again, causing the action to be called again
// ... endless loop
this.props.updateEngagementAction()
}
}
您的实施当然会有所不同,但这将是导致发生的主要内容,因此您需要在任何代码路径导致您的操作中添加警卫条件。
对于上面的代码,您需要在发送操作或实施shouldComponentUpdate
或类似地进行更深入的道具比较以防止不必要的更新之前检查逃生条件,因此,它不会在componentDidUpdate
方法中达到该动作代码
edit 这是在添加反应代码之前编写的。在这里,我指的是在componentDidUpdate
中没有防护的动作,但是当在通过Prop Change触发的任何其他生命周期方法中调用时,也适用了相同的操作,在这种情况下为componentWillRecieveProps
。公平地说,它确实已经有一个警卫,但是由于需要更深入的道具检查,因此从未返回错误,因此导致循环通过willreceive -> true -> action -> reducer -> willreceive -> true ........