ReactJS:setState之后未捕获的RangeError

时间:2015-04-08 09:07:41

标签: javascript canvas reactjs reactjs-flux

我正在尝试使用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;

感谢任何帮助,谢谢!

0 个答案:

没有答案