0

I'm trying to add dynamically react components into other react component when I press a button, rigth now I'm doing that using jQuery but the code is Awful. The principal idea is when I press <Button onClick={this.addProcess} data-mode="Hadoop"><Icon name="plus"/></Button> a the process will be attached in the server. this is handle by onClick={this.addProcess} that has all the logic to does it.

My code using Jquery:

var React = require('react');
var ReactDOM = require('react-dom');
var {Icon} = require('react-fa');
var moment = require('moment');
var TimeAgo = require('react-timeago')

var {
    ButtonGroup,
    DropdownButton,
    MenuItem,
    Button,
    Grid,
    Row,
    Col
} = require('react-bootstrap');

var ServerCanvas = React.createClass({
        addProcess: function(event) {
    // console.log(event.currentTarget.dataset.mode)


    var process = event.currentTarget.dataset.mode;
    var processDiv;

    switch (process) {
        case "Hadoop":
            processDiv = ` <div class="Grid-cell Grid" style="flex-flow: column nowrap; background: linear-gradient(135deg, rgb(244, 143, 177) 0%, rgb(194, 24, 91) 100%);">
            <div class="Grid-cell" style="font-size: 150%;">Hd</div>
            <div class="Grid-cell" style="font-size: 75%;">Hadoop</div>
            <div class="Grid-cell" style="font-size: 75%; color: rgb(0, 0, 0);">
            </div>
          </div>`;
            break;
        default:

    }

    var server = $('#servers').find('.test').not('.complete').first();

    if (server.children().length < 3) {

        server.append(processDiv); ///Append the new process

        if (server.first().children().length === 3) {
            server.addClass('complete');
        }
    }
},

    render: function() {
        return (
            <div className="">
                <Grid className="no-margin-padding container-hack">
                    <Row>
                        <Col md={4} className='grey-box'>
                            <Row className="rowHeight">
                                <Col md={6} className='text-center rowButton_Mid_Height'>
                                    <div className="pull-right">
                                        <Button bsClass='btn btn-default btn-lg btn-round' onClick={this.addServer}><Icon name="plus"/></Button>
                                        <div>Add server</div>
                                    </div>
                                </Col>
                                <Col md={6} className='text-center rowButton_Mid_Height'>
                                    <div className="pull-left">
                                        <Button bsClass='btn btn-default btn-lg btn-round' onClick={this.removeServer}><Icon name="minus"/></Button>
                                        <div>Destroy Server</div>
                                    </div>
                                </Col>
                            </Row>

                        </Col>
                        <Col md={8} className='black-box'>
                            <h1>Server Canvas</h1>
                            <div id='servers' className="serverContainer">
                                <div className="test grey-box">
                                    <div className='text-center'>Server 0</div>
                                </div>
                            </div>
                        </Col>
                    </Row>
                    <Row>
                        <Col xs={4} md={4} className=''>
                            <Row>
                                <Col xs={12} md={12} className=''>
                                    <div>
                                        <div className='HadoopBackground pull-left'>
                                            &nbsp;
                                        </div>
                                        Hadoop
                                        <div className='pull-right'>
                                            <Button bsClass='btn btn-default btn-xs btn-round HadoopBackgroundButton'><Icon name="minus"/></Button>
                                            <Button bsClass='btn btn-default btn-xs btn-round HadoopBackgroundButton' onClick={this.addProcess} data-mode="Hadoop"><Icon name="plus"/></Button>
                                        </div>
                                    </div>
                                </Col>
                            </Row>
                        </Col>
                    </Row>
                </Grid>
            </div>
        )
    }
});

ReactDOM.render(
    <ServerCanvas/>, document.getElementById('app'));

But that I'm looking for is create other react component (named Process in the code below) and When I press the button and addProcess is fired insert the Process component (Some code was removed):

var Process = React.createClass({
  render: function() {
    return (
      <div className="Grid-cell Grid">
      <div className="Grid-cell" >Hd</div>
      <div className="Grid-cell" >Hadoop</div>
      <div><time className='loaded timeago'></time></div>
      <div className="Grid-cell" >
      </div>
    </div>
    );
  }
})


addProcess: function(event) {
    // console.log(event.currentTarget.dataset.mode)


    var process = event.currentTarget.dataset.mode;
    var processDiv;

    var server = $('#servers').find('.test').not('.complete').first();

    if (server.children().length < 3) {
        console.log('puedo crear hijos');
          server.append(<Process />); //Add the new process but nothing happend.


        if (server.first().children().length === 3) {
            server.addClass('complete');
        }
    }
}

2 Answers 2

1

If you make a small adjustment to represent the current servers as an array in state, you can just iterate over all servers that have been added. Here is a stripped down version to demonstrate how you might go about that:

var ServerCanvas = React.createClass({
    // represent servers in state
    getInitialState: function() {
        return {
            servers: []
        }
    },
    // add new server to state
    addService: function(event) {
        this.setState({
            servers: this.state.servers.concat(event.currentTarget.dataset.mode)
        });
    },
    render: function() {
        return (
            <div>
                <h3>Servers</h3>
                <div className="servers">
                    {this.state.servers.map(function(server) {
                        return (
                            <div className="Grid-cell Grid" style="flex-flow: column nowrap; background: linear-gradient(135deg, rgb(244, 143, 177) 0%, rgb(194, 24, 91) 100%);">
                                <div class="Grid-cell" style="font-size: 75%;">{server}</div>
                                <div class="Grid-cell" style="font-size: 75%; color: rgb(0, 0, 0);">
                                </div>
                           </div>
                        )
                    })}
                </div>
            </div>
        )
    }
})

You could also split the Server into its own component:

var Server = React.createClass({
    render: function() {
        return (
            <div className="Grid-cell Grid" style="flex-flow: column nowrap; background: linear-gradient(135deg, rgb(244, 143, 177) 0%, rgb(194, 24, 91) 100%);">
                <div class="Grid-cell" style="font-size: 75%;">{this.props.serviceName}</div>
                <div class="Grid-cell" style="font-size: 75%; color: rgb(0, 0, 0);">
                </div>
           </div>
        )
    }
})

and change ServerCanvas render to:

{this.state.servers.map(function(server) {
    return <Server serviceName={server} />;
})}
Sign up to request clarification or add additional context in comments.

Comments

0

You should create a separated component and import it in your file, something like a ProcessComponent.

To add multiple stances of it, you should have an array of this components in your state, so when you need to add another you just push a value to this array you have in the State and use setState to handle render and update.

Something like this on render:

render() {
    var self = this;
    //This "self" here is because inside the loop below, the "this" context is going to be Jquery and not your Class. So you keep it in a separated value just for refence purpose. Like passing a callBack as in the example.
    var processComponent = this.state.processOnState.map(function(item, i) 
    {
        return (
                <Process key={"process"+i} ref={"process"+i} anyCallback={self.callBackMethodForParent.bind(self)} dataForProcess={item.dataToComponent} />
                );
    }.bind(this));
return (
 <div>
      <Col md={8} className='black-box'>
           <h1>Server Canvas</h1>
           <div id='servers' className="serverContainer">
                <div className="test grey-box">
                     <div className='text-center'>Server 0</div>
                 </div>
                 {processComponent}
           </div>
      </Col>
 </div>
)

So once you update the data you can trigger an update by using:

setState({processOnState:[{dataToComponent:1},{dataToComponent:2}]})

By default react should always handle all the render and updates, it has a logic that runs throught the DOM and finds out what has changed, and then just re-render it. You can trigger this behavior by using setState, thats the point.

Ref: https://facebook.github.io/react/docs/component-api.html#setstate

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.