5

I'm creating a web app which would allow the user to drag and drag multiple pieces on screen, with each one holding individual specific data. If the user would want to add more pieces onto the screen, they would simply click a button, and another piece would appear. I used the React DND (Drag and Drap) library to keep my components decoupled, and that worked fine, thus far. The issue is with the dynamic feature of adding more pieces on screen. Currently (in the Child code below), I'm getting the old state object, performing a shallow copy, and merging the newly created object with the pre-existing state object, and updating the state when finished. But, each time I perform this operation, everything works fine (new pieces generated on screen) until I go to move a new piece and I ge the following error:

Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state.

How can I go about getting out of this error, and having the state object update.

Note: The button (in the screenshot below), shows the current count of the amount of objects in the State object. So below I added 7 objects into the State

Screenshot of App: enter image description here Parent:

  import React, { Component, PropTypes } from 'react';
    import Header from '../../components/Header/header';
    import Footer from '../../components/Footer/footer';
    import Student from '../../components/box1/box1';
    import Box from '../../components/box2/box2';
    import { DragDropContext } from 'react-dnd';
    import HTML5Backend from 'react-dnd-html5-backend';
    require('./home.css');


var Home = React.createClass({
  getDefaultProps: function(){

    return{ count: 3 }  
  },

  getInitialState: function(){
     return{ count: this.props.count }
  },

  add: function(){
     this.setState({ count: this.state.count + 1 });
  },

  render() {

    return (
        <div id="main">
              <Box count = {this.state.count}/>
              <button count = {this.state.count} onClick = {this.add} > {this.state.count} </button>
          </div>

    );
  }
});

export default DragDropContext(HTML5Backend)(Home);

Child:

import React from 'react';
var ItemTypes = require('../box1/Constants').ItemTypes;
var DropTarget = require('react-dnd').DropTarget;
var Student = require('../box1/box1');
import update from 'react/lib/update';


require('./box2.css');

var BoxSource = {
  drop: function (props, monitor, component) {  
    const item = monitor.getItem();
    console.log(item);
    const delta = monitor.getDifferenceFromInitialOffset();
    const left = Math.round(item.left + delta.x);
    const top = Math.round(item.top + delta.y);
    const id = item.id;

    component.move(id, left, top);
       }
};

function collect(connect, monitor) {
  return {
    connectDropTarget: connect.dropTarget(),
    didDrop: monitor.didDrop(),
    source: monitor.getSourceClientOffset(),
    item: monitor.getItem(),
    drop: monitor.didDrop(),
    result: monitor.getDropResult()
  };
}

var box2 = React.createClass({

    getInitialState: function() {
    return  { Students: {
        '0': { top: 20, left: 80 },
        '1': { top: 180, left: 20 },
        '2': { top: 130, left: 20 },

      }
    };
  },


componentWillReceiveProps: function(nextProps) {
     var i = this.props.count;
     console.log(this.state.Students);
     var obj = update(this.state,{ 

      Students:{ 
                $merge:{
                  [i]:{
                    top: 10,
                     left:10 
                    }
                  }
                }        
             });

    this.setState(obj);
  },

  move: function(id,left,top){
     this.setState(update(this.state,{
          Students:{ 
               [id]:{
                    $merge:{
                     left:left,
                     top: top
                    }
                  }
                }
            }));
  },

  render:function() {
    const { Students } = this.state;
    var connectDropTarget = this.props.connectDropTarget;
    return connectDropTarget(
      <div id = "box">
            {Object.keys(Students).map(key =>{
                const { left, top, title } = Students[key];
                 return(
                            <Student key = {key} id = {key} left = {left}
                            top = {top}> </Student>
                         );})}
      </div>
    );
  }
});

module.exports = DropTarget(ItemTypes.STUDENT, BoxSource, collect)(box2);
markthethomas
  • 4,391
  • 2
  • 25
  • 38
Justin E. Samuels
  • 867
  • 10
  • 28
  • Does the error occur when you start dragging the piece or when you try dropping the piece? If it's the former can you post the Student component? – Ben Hare May 28 '16 at 18:16

1 Answers1

0

It looks like the problem might lay inside your "Student" component. Running the above code without the "Student" component (as it is not posted), works fine. If you haven't solved this yet, please also post box1.js.

omerts
  • 8,485
  • 2
  • 32
  • 39