Not removing them resulted in leaks as we would hold on to removed nodes forever.
This really showed up with images and the load event where we would unmount and create a new img with the same react id as the old one. We properly cleared and primed the caches but we would handle the load event for both nodes. We would eventually hit an invariant in that path as we tried to handle the event for the removed node, which no longer matched the node we had in the cache.
By forcefully removing the listener, we'll avoid this problem entirely and we should leak fewer DOM nodes.
If the event is on the window object, topScroll, for instance, the topLevelTarget will not have getAttribute defined. Restore the previous `|| !topLevelTarget.attributes` check to avoid an error on every scroll.
cf. #1376.
This is useful for SVG. Dynamically adding and removing `<title>` elements in SVG still won't work properly because of getMarkupWrap but this at least lets you include it in initial render and then unmount the entire `<svg>` without problems.
For boolean-like objects, I've added hasOwnProperty checks in addition to the existing truthiness check even though for most of these dicts, we leave out false keys instead of setting them explicitly to false.
In DOMPropertyOperations, we don't need to check hasOwnProperty if the property is in isStandardName because (with the exception of getPossibleStandardName) the dicts on DOMProperty will now be consistently populated with every valid attribute.
With this, multiple setState calls triggered by a componentDidUpdate handler (or similar) will be batched together, regardless of if the original setState call was in a batching context.
I also cleaned up some inconsistencies with the order of component updates and callbacks in situations where one component's update directly causes another to update.
Fixes#1147. Helps with #1353 and #1245 as well, though doesn't completely fix them yet.
Test Plan:
grunt test
Currently require('ReactDefaultPerf').printExclusive() shows render
time and aggregate componentMount time.
This makes it show exclusive mount time by tracking a stack.
This copies the propType and contextType validation to a wrapper around the
descriptor factory. By doing the validation early, we make it easier to track
down bugs. It also prepares for static type checking which should be done at the
usage site.
This validation is not yet active and is just logged using monitorCodeUse. This
will allow us to clean up callsites which would fail this new type of
validation.
I chose to copy the validation instead of abstracting it out to a common abstraction. This is just an
intermediate step to avoid spamming consoles. The original validation in the instance will be deleted as soon as we can turn on the warnings at the callsite. Copy+Delete makes this a more a much cleaner diff review/history.
Additionally, getDefaultProps are moved to become a static function which is
only executed once. It should be moved to statics but we don't have a
convenient way to merge mixins in statics right now. Deferring to ES6 classes.
This is still a breaking change since you can return an object or array from
getDefaultProps, which later gets mutated and now the shared instance is
mutated. Mutating an object that is passed into you from props is highly
discouraged and likely to lead to subtle bugs anyway. So I'm not too worried.
The defaultProps are now resolved in the descriptor factory. This will enable
a perf optimizations where we don't create an unnecessary object allocation
when you use default props. It also means that ReactChildren.map has access to
resolved properties which gives them consistent behavior whether or not the
default prop is specified.
This is a breaking change since it can affect how mapping over children and
transferPropsTo works together with defaultProps.
KeyboardEvent now normalizes "charCode", "keyCode", "which" across all browsers
KeyboardEvent has partial "key"-support for KeyDown/KeyUp and full "key"-support for KeyPress.
KeyboardEvent, MouseEvent and TouchEvent now has "getModifierState", polyfill when not implemented.
Some Android versions have the "transition" and "animation" properties
set on element style objects despite not supporting un-prefxied animations
and transitions. This change adds an additional sanity check to make sure
the correct event handlers are added for transition groups.
In IE10/11, it is apparently possible to have a Selection or Range object that has the following properties:
- `anchorNode` === `focusNode` (Selection) or `startContainer` === `endContainer` (Range)
- `anchorOffset` === `focusOffset` (Selection) or `startOffset` === `endOffset` (Range)
- `isCollapsed` === `false` (Selection) or `collapsed` === `false` (Range)
As defined in http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html, this doesn't really make sense. Since the nodes and offsets are the same, the "collapsed" value should be `true`.
Moreover, when calling `selection.toString()` in this case, it appears that the entire text contents of `body` -- including `<script>` tag contents -- are considered within the selection. I thought maybe the selected nodes were missing from the DOM or something, but no, they're there.
Sidestep all of this in `ReactDOMSelection` by calculating the `collapsed` property manually and setting the selection length directly to zero if it is actually collapsed.
Side note: I think that for selection restoration on contenteditables, we shouldn't try to do this offset calculation. We should just use the structure provided natively (nodes and offsets) since we can restore using that structure as well.
Previous behavior: `transferPropsTo(<div style={{color: 'red'}} />)` would get `color` overriden if we transfer in a `style={{color: 'blue'}}`. This is inconsistent with how other props are transfered.
This simply reverses the order of arguments.
closes#1435
This makes it a little easier to add SVG properties. It also makes use of that injection that we claim is easy to use and will likely start playing a bigger part soon.
Closes#1009