克隆已安装的组件

时间:2014-12-12 16:16:05

标签: javascript reactjs

我正在尝试构建一个使用拖放行为的应用程序,并且需要将拖动的组件克隆到DOM中的其他位置。由于组件已经安装,尝试再次安装它会导致浏览器挂起。

尝试使用cloneWithProps会导致Cannot read property 'defaultProps' of undefined错误。

这是一个测试用例:

var TestCase = React.createClass({
  getInitialState () {
    return {
      draggingItem: null
    }
  },

  render () {
    return <div>
      <ExampleComponent onClick={this.setDraggingItem} />
      {this.state.draggingItem}
    </div>
  },

  setDraggingItem (component) {
    // This gives `Cannot read property 'defaultProps' of undefined`
    //React.addons.cloneWithProps(component)

    // This crashes the browser
    //this.setState({ draggingItem: component })
  }
})

var ExampleComponent = React.createClass({
  render () {
    return <div onClick={this.handleOnClick}>Hello World</div>
  },

  handleOnClick (event) {
    this.props.onClick(this)
  }
})

React.render(<TestCase />, document.body)

当然,我可以简单地在component.getDOMNode()中克隆setDraggingItem,但它真的好像渲染组件或调用cloneWithProps应该有效吗?

2 个答案:

答案 0 :(得分:1)

您需要确保使用相同的道具创建新组件,而不是多次安装相同的道具。首先,设置一个返回实例化组件的函数(这里更容易删除JSX):

function getComponent(props) {
   return ExampleComponent(props);
}

然后在你的TestCase渲染中:

return (<div>
    { getComponent({ onClick: this.setDraggingItem }) }
    { this.state.draggingItem }
</div>);

这将创建第一个组件。然后创建一个克隆:

setDraggingItem(component) {
    var clone = getComponent(component.props);
}

这涉及克隆部分。你还有一些拖拽和渲染要弄清楚。

答案 1 :(得分:1)

创建元素所需的两件事是:组件类(例如ExampleComponent)及其props。 cloneWithProps仅用于render,并且仅用于来自在另一个组件的渲染中创建的props的元素。您不应该保存元素,或者将它们传递给渲染中的其他组件。而是传递对象(props)和组件类。

由于您需要知道要在第一时间呈现它的props和组件类,因此您可以在TestCase中处理所有这些。

var TestCase = React.createClass({
  getInitialState () {
    return {
      draggingItem: null,
      draggingItemProps: null
    }
  },

  render () {
    return <div>
      <ExampleComponent onClick={this.setDraggingItem.bind(null, 
      /* the component class */         ExampleComponent, 
      /* the props to render it with */ null
      )} />
      { 
        this.state.draggingItem && React.createElement(
          this.state.draggingItem, 
          this.state.draggingItemProps
        )
      }
    </div>
  },

  setDraggingItem (component, props, event) {
    this.setState({ draggingItem: component, draggingItemProps: props })
  }
});

var ExampleComponent = React.createClass({
  render () {
    return <div onClick={this.handleOnClick}>Hello World</div>
  },
  // just defer the event
  handleOnClick (event) {
    this.props.onClick(event)
  }
});

如果您希望在TestCase组件之外使这些有效,请确保在props中没有绑定到TestCase的任何函数。还要确保没有儿童支持其中的反应元素。如果孩子是相关的,请提供重建它们所需的{componentClass,props}结构。

很难说出你的实际要求是什么,但希望这足以让你开始。