Summary:
e.g.
propTypes: {
foo: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number
]);
}
to do this, I exposed a `.weak` chainable validator that returns instead of throws, e.g.
React.PropTypes.string.isRequired.weak
React.PropTypes.string.weak
which returns true or false. Technically, `React.PropTypes.string.weak.isRequired` also exists, but `oneOfType` will never call it. Might be useful to people creating custom validators though.
Since we use keyMirror() and invariant() messages are only shown in __DEV__, we don't have to do manual constant->string translation. Also fixes a few
undefined keys that just happened to work before.
As an added bonus, the jasmine web interface now groups tests by file.
Test Plan:
grunt test passes on b2507066, the parent of 566f8b2e (which committed a workaround for buggy module mocking).
We can already access the DOM node using `this.getDOMNode()`. Passing it as an argument was a bad decision.
Previous API:
```
componentDidMount(DOMElement rootNode)
componentDidUpdate(object prevProps, object prevState, object prevContext, DOMElement rootNode)
```
Next API:
```
componentDidMount()
componentDidUpdate(object prevProps, object prevState, object prevContext)
```
callbacks like shouldComponentUpdate, componentDidUpdate, etc. were getting the full, unsanitized context, instead of the one that's been filtered down to only the fields allowed to be visible by contextTypes.
Context is adding another argument that shifts all of them by one. Since we can already use this.getDOMNode(), it doesn't really make sense to pass it as an argument to that function.
Depends on #575; fixes#570. Now we'll be in trouble if someone tries to share objects between calls to getDefaultProps but that was already true of getInitialState and I haven't heard any complaints there.
This is the same number of allocations as before; we're just copying props in the other direction. (In any case, the copy happens only on mount and there are a couple dozen costlier things we're doing already at that time.)
This module-level mock() seems to have been interfering with other tests (26 specs failing). We don't have any other tests that do a module-level mock() so I'm going to assume it isn't supported in the open-source test runner right now. I changed it so only ReactEventEmitter.handleTopLevel is mocked; doing so made ReactEventEmitter complain that TopLevelCallbackCreator wasn't defined so I switched the ReactMount references to use React directly so that ReactDefaultInjection would kick in properly.
With this, all the tests pass.
When events are captured, the nearest React-rendered ancestor is found and events are propagated to its tree. This causes issues when components are nested as only the innermost component receives the events.
This change modifies this behaviour so events propagate all the way up the DOM hierarchy. To reduce the performance cost, this DOM traversal is only done if the component is actually nested (determined by the `containerIsNested` map which is lazily initialised).
Summary:
adds `this.context` which you can think of as implicit props, which are passed automatically down the //ownership// hierarchy.
Contexts should be used sparingly, since they essentially allow components to communicate with descendants (in the ownership sense, not parenthood sense), which is not usually a good idea. You probably would only use contexts in places where you'd normally use a global, but contexts allow you to override them for certain view subtrees which you can't do with globals.
The context starts out `null`:
var RootComponent = React.createClass({
render: function() {
// this.context === null
}
});
You should **never** mutate the context directly, just like props and state.
You can change the context of your children (the ones you own, not `this.props.children` or via other props) using the new `withContext` method on `React`:
var RootComponent = React.createClass({
render: function() {
// this.context === null
var children = React.withContext({foo: 'a', bar: 'b'}, () => (
// In ChildComponent#render, this.context === {foo: 'a', bar: 'b'}
<ChildComponent />
));
// this.context === null
}
});
Contexts are merged, so a component can override its owner's context **for its children**:
var ChildComponent = React.createClass({
render: function() {
// this.context === {foo: 'a', bar: 'b'} (for the caller above)
var children = React.withContext({foo: 'c'},() => (
// In GrandchildComponent#render,
// this.context === {foo: 'c', bar: 'b'}
<GrandchildComponent />
));
// this.context === {foo: 'a', bar: 'b'}
}
});
Reported on Twitter by AirBnb (who are integrating React into their open-source JS framework). They made a mistake and passed a string in as the
component. We should have a better error message for that.
This renames receiveProps and changes it to take the next component to copy props from instead of just the props. That is,
component.receiveComponent(nextComponent, transaction)
instead of
component.receiveProps(nextComponent.props, transaction)
This is a precursor to adding contexts, which will also need to get propagated just like props. This change allows ReactCompositeComponent to override `receiveProps` and do something like
this._pendingContext = nextComponent.context;