-
Notifications
You must be signed in to change notification settings - Fork 47.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ReactLink: two-way binding for React
This introduces `ReactLink` which is a super lightweight way to do two-way binding for React. If you want to use a controlled form input today, it's a lot of lines of code: http://jsfiddle.net/T3z3v/ Look how many times `name` is repeated in there. And you have to remember to wire up event handles and pass the right state and right event handler for *each* form field. It's really annoying. With ReactLink, you can "link" a form value to a state field. It's just some simple sugar around the value prop/onChange convention: https://gist.github.com/petehunt/6689857 Ah, much nicer! And requires very little core changes or extra bytes. `ReactLink` just wraps the current value and "request change" handler into a little object and provides some sugar to create some from composite component state.
- Loading branch information
Showing
10 changed files
with
343 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/** | ||
* Copyright 2013 Facebook, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* @providesModule LinkedStateMixin | ||
* @typechecks static-only | ||
*/ | ||
|
||
"use strict"; | ||
|
||
var ReactLink = require('ReactLink'); | ||
var ReactStateSetters = require('ReactStateSetters'); | ||
|
||
/** | ||
* A simple mixin around ReactLink.forState(). | ||
*/ | ||
var LinkedStateMixin = { | ||
/** | ||
* Create a ReactLink that's linked to part of this component's state. The | ||
* ReactLink will have the current value of this.state[key] and will call | ||
* setState() when a change is requested. | ||
* | ||
* @param {string} key state key to update. Note: you may want to use keyOf() | ||
* if you're using Google Closure Compiler advanced mode. | ||
* @return {ReactLink} ReactLink instance linking to the state. | ||
*/ | ||
linkState: function(key) { | ||
return new ReactLink( | ||
this.state[key], | ||
ReactStateSetters.createStateKeySetter(this, key) | ||
); | ||
} | ||
}; | ||
|
||
module.exports = LinkedStateMixin; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/** | ||
* Copyright 2013 Facebook, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* @providesModule ReactLink | ||
* @typechecks static-only | ||
*/ | ||
|
||
"use strict"; | ||
|
||
/** | ||
* ReactLink encapsulates a common pattern in which a component wants to modify | ||
* a prop received from its parent. ReactLink allows the parent to pass down a | ||
* value coupled with a callback that, when invoked, expresses an intent to | ||
* modify that value. For example: | ||
* | ||
* React.createClass({ | ||
* getInitialState: function() { | ||
* return {value: ''}; | ||
* }, | ||
* render: function() { | ||
* var valueLink = new ReactLink(this.state.value, this._handleValueChange); | ||
* return <input valueLink={valueLink} />; | ||
* }, | ||
* this._handleValueChange: function(newValue) { | ||
* this.setState({value: newValue}); | ||
* } | ||
* }); | ||
* | ||
* We have provided some sugary mixins to make the creation and | ||
* consumption of ReactLink easier; see LinkedValueMixin and LinkedStateMixin. | ||
*/ | ||
|
||
/** | ||
* @param {*} value current value of the link | ||
* @param {function} requestChange callback to request a change | ||
*/ | ||
function ReactLink(value, requestChange) { | ||
this.value = value; | ||
this.requestChange = requestChange; | ||
} | ||
|
||
module.exports = ReactLink; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* Copyright 2013 Facebook, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* @jsx React.DOM | ||
* @emails react-core | ||
*/ | ||
|
||
"use strict"; | ||
|
||
/*jshint evil:true */ | ||
|
||
describe('LinkedStateMixin', function() { | ||
var LinkedStateMixin; | ||
var React; | ||
var ReactLink; | ||
|
||
beforeEach(function() { | ||
LinkedStateMixin = require('LinkedStateMixin'); | ||
React = require('React'); | ||
ReactLink = require('ReactLink'); | ||
}); | ||
|
||
it('should create a ReactLink for state', function() { | ||
var Component = React.createClass({ | ||
mixins: [LinkedStateMixin], | ||
|
||
getInitialState: function() { | ||
return {value: 'initial value'}; | ||
}, | ||
|
||
render: function() { | ||
return <span>value is {this.state.value}</span>; | ||
} | ||
}); | ||
var container = document.createElement('div'); | ||
var component = React.renderComponent(<Component />, container); | ||
var link = component.linkState('value'); | ||
expect(component.state.value).toBe('initial value'); | ||
expect(link.value).toBe('initial value'); | ||
link.requestChange('new value'); | ||
expect(component.state.value).toBe('new value'); | ||
expect(component.linkState('value').value).toBe('new value'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/** | ||
* Copyright 2013 Facebook, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* @providesModule LinkedValueMixin | ||
* @typechecks static-only | ||
*/ | ||
|
||
"use strict"; | ||
|
||
var invariant = require('invariant'); | ||
|
||
/** | ||
* Provide a linked `value` attribute for controlled forms. You should not use | ||
* this outside of the ReactDOM controlled form components. | ||
*/ | ||
var LinkedValueMixin = { | ||
_assertLink: function() { | ||
invariant( | ||
this.props.value == null && this.props.onChange == null, | ||
'Cannot provide a valueLink and a value or onChange event. If you ' + | ||
'want to use value or onChange, you probably don\'t want to use ' + | ||
'valueLink' | ||
); | ||
}, | ||
|
||
/** | ||
* @return {*} current value of the input either from value prop or link. | ||
*/ | ||
getValue: function() { | ||
if (this.props.valueLink) { | ||
this._assertLink(); | ||
return this.props.valueLink.value; | ||
} | ||
return this.props.value; | ||
}, | ||
|
||
/** | ||
* @return {function} change callback either from onChange prop or link. | ||
*/ | ||
getOnChange: function() { | ||
if (this.props.valueLink) { | ||
this._assertLink(); | ||
return this._handleLinkedValueChange; | ||
} | ||
return this.props.onChange; | ||
}, | ||
|
||
/** | ||
* @param {SyntheticEvent} e change event to handle | ||
*/ | ||
_handleLinkedValueChange: function(e) { | ||
this.props.valueLink.requestChange(e.target.value); | ||
} | ||
}; | ||
|
||
module.exports = LinkedValueMixin; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.