简体   繁体   中英

How to make component instances in Reactjs

When I call ReactDom.render in init() only one g tag is created and all circles are created inside this g tag. but I want that on every ReactDom.render call a separate g tag must be created. My knowledge of components in React is that we can instantiate as many components as we want using React.createClass . How can I do this?

var Rect = React.createClass({
  render: function() {
    return (
      React.createElement('circle', {
        cx: this.props.cx,
        cy: this.props.cy,
        r: this.props.r,
        fill: '#00ff00'
      });
    );
  }
});

var globalArray = [];
var someFunc = function(cx, cy, r) {
  var Factory = React.createClass({
    render: function() {
      var localArray = [];
      for(var i = 0; i < 1; i++) {
        localArray[i] = React.createElement(Rect, {
          key: globalArray.length,
          cx: cx,
          cy: cy,
          r: r
        })
      }

      globalArray[globalArray.length] = localArray[0];
      return (
        React.createElement('g', {}, globalArray)
      )
    }
  });
  return Factory;
}

var randomNumber = function (x,y) {
  return ~~(Math.floor(((Math.random()*x) + y )));
}

var obj = {
  init: function() {
    var element;
    for(var i = 0; i < 100; i++) {
      var cx = randomNumber(1200,40);
      var cy = randomNumber(600,40);
      var r = randomNumber(30,20);
      element = someFunc(cx,cy,r);
      ReactDOM.render(
        React.createElement(element,{}),         
        document.getElementById('svg')
      );
    }       
  }
}

You'll probably find that you benefit from letting the structure of your code be defined by React components, rather than your own functions and global variables.

Generally, if you find yourself calling ReactDOM.render lots of times, then something has probably gone wrong.

Top Level Component

Rather than rendering 100 components into one element, define a top level component which is made up of 100 subcomponent instances, then render that once.

var Graphics = React.createClass({
  // ...
});

ReactDOM.render(
  React.createElement(Graphics, null),
  document.getElementById('svg')
);

We'll create a Graphics component that we can use as a parent for the rest of the components. We only need to render this once .

State

Rather than storing your list of circles in a global array, use the state property on your new top level component. This way, whenever you update it, the component will re-render to reflect the changes.

getInitialState: function() {
  // by default there are no circles (empty array)
  return { circles: [] };
},
componentWillMount: function() {
  var circles = [];

  for(var i = 0; i < 100; i++) {
    // rather than storing actual circles, we just store
    // the props that are needed to create them
    circles.push({
      cx: randomNumber(1200, 40),
      cy: randomNumber(600, 40),
      r: randomNumber(30,20)
    });
  }

  this.setState({ circles: circles });
}

getInitialState allows us to define default values for the properties on this.state and componentWillMount allows to run code just before the component is rendered in the DOM.

Render

Now that the Graphics component knows about the circles list, we have to describe the way it should be rendered.

render: function() {
  var circles = this.state.circles.map(function(props) {
    return React.createElement(Circle, props);
  });

  return React.createElement('g', null, circles);
}

This function uses map to create a Circle component using the props that we stored in this.state.circles .

Conclusion

React is most effective when you structure your components to live within one top level container component, like we've created here. Rather than ever doing any imperative actions (like looping and rendering components each time) you should look for declarative alternatives.

React wants you to tell it what you want, not how it should be done.

In this case, what you wanted was a component with a number of randomly sized and positioned circles inside it, but what you tried to do was explain to React how it should go about making that happen.

var Circle = React.createClass({
  render: function() {
    // ...
  }
});

var Graphics = React.createClass({
  getInitialState: function() {
    // ...
  },
  componentWillMount: function() {
    // ...
  },
  render: function() {
    // ...
  }
});

The resulting code should not only be shorter and easier to follow, but also easy to refactor. Without much work you could move configuration details — like the number of circles — out to being a prop of Graphics .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM