尊重“valueLink”的自定义ReactJS组件

7
我正在构建一个自定义的ReactJS组件(一个“Select2”下拉库包装器),希望使用"valueLink"参数实现标准的双向绑定助手函数支持。
然而,似乎处理"valueLink"参数的mixin仅适用于标准组件,而不适用于自定义组件。
是否有一种方式可以使我的组件自动实现标准的valueLink行为,或者我需要显式解析并实现这种支持(可能会引入不存在于基础库中的错误或奇怪的行为)?
1个回答

7
使用LinkedStateMixin时从this.linkState返回的对象具有两个相关属性:valuerequestChange()。只需像如果它们已通过valueonChange传递给您的自定义组件一样,使用这两个属性作为您的值和更改处理程序。
下面是一个示例,展示了包装jQuery颜色选择器的组合组件; 它既可以使用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>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接