我正在尝试使用ReactJS和Flux创建一个简单的绘图应用程序。但是,我遇到了一个错误[Uncaught RangeError:超出最大调用堆栈大小](更具体地说是一个ReactJS问题)我已经尝试了一段时间了。它发生在我尝试在组件中执行setState()时。以下是我的代码的一部分,以更好地说明我的问题。
DrawingCanvas.react.js
var React = require('react');
var MouseInteractionsMixin = require('../utils/MouseInteractionsMixin');
var StrokeActionCreators = require('../actions/StrokeActionCreators');
var StrokeStore = require('../stores/StrokeStore');
function getStateFromStores() {
return {
currentStroke: StrokeStore.getCurrentStroke()
};
}
var DrawingCanvas = React.createClass({
mixins: [MouseInteractionsMixin],
styles: {
canvas: {
border: '1px solid black'
}
},
getInitialState: function() {
return getStateFromStores();
},
componentWillMount: function() {
StrokeStore.addChangeListener(this._update);
},
componentDidMount: function() {
this._onChange();
},
componentDidUpdate: function() {
this._onChange();
},
_onChange: function() {
if(this.state.dragging) {
StrokeActionCreators.beginStroke(this.state.mouse.point);
} else {
if(this.state.mouse.event == 'mouseup') {
StrokeActionCreators.endStroke(this.state.currentStroke);
}
}
},
_update: function() {
this.setState(getStateFromStores()); // where the problem occurs
context = this.getDOMNode().getContext('2d');
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
this._draw(context);
},
_draw: function(context) {
context.strokeStyle = '#000000';
context.lineJoin = 'round';
context.lineWidth = 5;
// Draw current stroke (incompleted)
for(var index = 1; index < this.state.currentStroke.points.length; index++) {
context.beginPath();
context.moveTo(this.state.currentStroke.points[index - 1].x, this.state.currentStroke.points[index - 1].y);
context.lineTo(this.state.currentStroke.points[index].x, this.state.currentStroke.points[index].y);
context.closePath();
context.stroke();
}
/*// Draw the other completed strokes
for(var strokeIndex = 0; strokeIndex < this.state.strokes.length; strokeIndex++) {
var stroke = this.state.strokes[strokeIndex];
for(var currentPointIndex = 1; currentPointIndex < stroke.points.length; currentPointIndex++) {
var previousPointIndex = currentPointIndex - 1;
context.beginPath();
context.moveTo(stroke.points[previousPointIndex].x, stroke.points[previousPointIndex].y);
context.lineTo(stroke.points[currentPointIndex].x, stroke.points[currentPointIndex].y);
context.closePath();
context.stroke();
}
}*/
},
render: function() {
return (
<canvas style={this.styles.canvas} width={this.props.width} height={this.props.height} />
);
}
});
module.exports = DrawingCanvas;
基本上,我正在尝试做的是在单击鼠标并在画布上开始移动时触发动作,该画布将鼠标位置数据发送到StrokeStore。 StrokeStore存储所有鼠标位置数据,因此最终DrawingCanvas组件请求数据(因此getStateFromStores()函数)并在画布上绘制,但是当我尝试在_update()函数中设置状态并尝试绘制时在画布上,会有大量的鼠标位置数据进入(即使稍微移动鼠标然后停止它),并且会出现错误“Uncaught RangeError:超出最大调用堆栈大小”。
我已经尝试过不将鼠标位置数据存储为组件的状态,而是将我在组件中使用的组件外部的变量分开,并且它工作得很好,所以我认为这是setState的一个问题( )。
我真的希望让它以状态(或任何其他方式)在商店中包含数据。
修改
StrokeStore.js
var AppDispatcher = require('../dispatchers/AppDispatcher');
var AppConstants = require('../constants/AppConstants');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var ActionTypes = AppConstants.ActionTypes;
var CHANGE_EVENT = 'change';
var _currentStroke = {
// Points array contains point objects with x and y variables
points: []
};
// Strokes array contains stroke objects with similar structure to currentStroke
var _strokes = [];
function _addPointToCurrentStroke(point) {
_currentStroke.points.push(point);
}
function _addStrokeToStrokes(stroke) {
_strokes.push(stroke);
}
function _clearCurrentStroke() {
_currentStroke = {
points: []
};
}
var StrokeStore = assign({}, EventEmitter.prototype, {
emitChange: function() {
this.emit(CHANGE_EVENT);
},
/**
* @param {function} callback
*/
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
},
getCurrentStroke: function() {
return _currentStroke;
},
getStrokes: function() {
return _strokes;
}
});
AppDispatcher.register(function(payload) {
var action = payload.action;
switch(action.type) {
case ActionTypes.BEGIN_STROKE:
_addPointToCurrentStroke(action.point);
break;
case ActionTypes.END_STROKE:
_addStrokeToStrokes(action.stroke);
_clearCurrentStroke();
break;
default:
}
StrokeStore.emitChange();
});
module.exports = StrokeStore;
感谢任何帮助,谢谢!