尊重'valueLink'的自定义ReactJS组件

时间:2014-09-23 02:17:46

标签: data-binding reactjs

我正在构建一个自定义的ReactJS组件(A' Select2'下拉列表包装器),并希望使用' valueLink'来实现对标准双向绑定帮助程序的支持。参数。

然而,似乎是mixin来处理' valueLink'参数仅适用于标准组件,而不适用于自定义组件。

是否有办法让我的组件自动实现标准的valueLink行为,或者我是否需要自己显式解析和实现此支持(可能会引入基本库中不存在的错误或奇怪的行为)< / p>

1 个答案:

答案 0 :(得分:7)

使用this.linkState时从LinkedStateMixin返回的对象有两个相关属性:valuerequestChange()。只需将这两个属性分别用作值和更改处理程序,就像它们已通过valueonChange传递给您的自定义组件一样。

以下是包装a jQuery color picker的复合组件的示例;它适用于valueLink以及标准valueonChange属性。 (要运行该示例,请展开“显示代码段”,然后单击底部的“运行代码段”。)

var ColorPicker = React.createClass({
  render: function() {
    return <div />;
  },

  getValueLink: function(props) {
    // Create an object that works just like the one
    // returned from `this.linkState` if we weren't passed
    // one; that way, we can always behave as if we're using
    // `valueLink`, even if we're using plain `value` and `onChange`.
    return props.valueLink || {
      value: props.value,
      requestChange: props.onChange
    };
  },

  componentDidMount: function() {
    var valueLink = this.getValueLink(this.props);

    jQuery(this.getDOMNode()).colorPicker({
      pickerDefault: valueLink.value,
      onColorChange: this.onColorChange
    });
  },

  componentWillReceiveProps: function(nextProps) {
    var valueLink = this.getValueLink(nextProps);
    var node = jQuery(this.getDOMNode());
    node.val(valueLink.value);
    node.change();
  },

  onColorChange: function(id, color) {
    this.getValueLink(this.props).requestChange(color);
  }
});

div.colorPicker-picker {
  height: 16px;
  width: 16px;
  padding: 0 !important;
  border: 1px solid #ccc;
  background: url(https://raw.github.com/laktek/really-simple-color-picker/master/arrow.gif) no-repeat top right;
  cursor: pointer;
  line-height: 16px;
}

div.colorPicker-palette {
  width: 110px;
  position: absolute;
  border: 1px solid #598FEF;
  background-color: #EFEFEF;
  padding: 2px;
  z-index: 9999;
}
  div.colorPicker_hexWrap {width: 100%; float:left }
  div.colorPicker_hexWrap label {font-size: 95%; color: #2F2F2F; margin: 5px 2px; width: 25%}
  div.colorPicker_hexWrap input {margin: 5px 2px; padding: 0; font-size: 95%; border: 1px solid #000; width: 65%; }

div.colorPicker-swatch {
  height: 12px;
  width: 12px;
  border: 1px solid #000;
  margin: 2px;
  float: left;
  cursor: pointer;
  line-height: 12px;
}
<script src="http://fb.me/react-with-addons-0.11.2.js"></script>
<script src="http://fb.me/JSXTransformer-0.11.2.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="https://dl.dropboxusercontent.com/u/113308/dnd/jsfiddle/jquery.colorPicker.min.js"></script>

<p><strong>With valueLink</strong></p>
<div id="app1"></div>
<hr>
<p><strong>With value and onChange</strong></p>
<div id="app2"></div>

<script type="text/jsx">
/** @jsx React.DOM */

var ApplicationWithValueLink = React.createClass({
  mixins: [React.addons.LinkedStateMixin],

  getInitialState: function() {
    return { color: "#FF0000" }
  },
  
  render: function() {
    return (
      <div>
        <div>
          <span style={{color: this.state.color}}>My Color Picker</span>
          <button onClick={this.changeColor.bind(null, "#FF0000")}>Red</button>
          <button onClick={this.changeColor.bind(null, "#00FF00")}>Green</button>
          <button onClick={this.changeColor.bind(null, "#0000FF")}>Blue</button>
          <input type="text" valueLink={this.linkState("color")} />
        </div>
        <div>
          <ColorPicker valueLink={this.linkState("color")} />
        </div>
      </div>
    );
  },
  
  changeColor: function(color) {
    this.setState({color: color});
  }
});

var ApplicationWithoutValueLink = React.createClass({
  getInitialState: function() {
    return { color: "#FF0000" }
  },
  
  render: function() {
    return (
      <div>
        <div>
          <span style={{color: this.state.color}}>My Color Picker</span>
          <button onClick={this.changeColor.bind(null, "#FF0000")}>Red</button>
          <button onClick={this.changeColor.bind(null, "#00FF00")}>Green</button>
          <button onClick={this.changeColor.bind(null, "#0000FF")}>Blue</button>
          <input type="text" value={this.state.color} onChange={this.changeColorText} />
        </div>
        <div>
          <ColorPicker value={this.state.color} onChange={this.changeColor} />
        </div>
      </div>
    );
  },
  
  changeColor: function(color) {
    this.setState({color: color});
  },
  
  changeColorText: function(evt) {
    this.changeColor(evt.target.value);
  }
});

var ColorPicker = React.createClass({
  render: function() {
    return (
      <div />
    );
  },
  
  getValueLink: function(props) {
    return props.valueLink || {
      value: props.value,
      requestChange: props.onChange
    };
  },
  
  componentDidMount: function() {
    var valueLink = this.getValueLink(this.props);

    jQuery(this.getDOMNode()).colorPicker({
      pickerDefault: valueLink.value,
      onColorChange: this.onColorChange
    });
  },
  
  componentWillReceiveProps: function(nextProps) {
    var valueLink = this.getValueLink(nextProps);
    var node = jQuery(this.getDOMNode());
    node.val(valueLink.value);
    node.change();
  },
  
  onColorChange: function(id, color) {
    this.getValueLink(this.props).requestChange(color);
  }
});

React.renderComponent(<ApplicationWithValueLink />, document.getElementById("app1"));
React.renderComponent(<ApplicationWithoutValueLink />, document.getElementById("app2"));
</script>