Custom ReactJS component that respects 'valueLink'
The object returned from this.linkState
when using the LinkedStateMixin
has two relevant properties: value
and requestChange()
. Simply use those two properties as your value and change handler, respectively, just as if they had been passed to your custom component via value
and onChange
.
Here's an example of a composite component that wraps a jQuery color picker; it works both with valueLink
and with standard value
and onChange
properties. (To run the example, expand the "Show code snippet" then click "" at the bottom.)
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>