Summary:
After #2570, `mountDepth` is only used to enforce that `setProps` and `replaceProps` is only invoked on the top-level component. This replaces `mountDepth` with a simpler `isTopLevel` boolean set by `ReactMount` which reduces the surface area of the internal API and removes the need to thread `mountDepth` throughout React core.
Reviewers: @sebmarkbage @zpao
Test Plan:
Ran unit tests successfully:
```
npm run jest
```
Summary:
Changes the way we instrument methods for `ReactPerf` so that developer tools can assign implicit method names to measured functions.
Reviewers: @zpao @sebmarkbage
This is part of moving more logic out of the base classes.
setProps, replaceProps etc. are not accessible from anything other than
ReactClass so we can safely move it to ReactCompositeComponent.
mountComponentIntoNode is tightly coupled to ReactMount. It's part of the
outer abstraction, the mount point, not the individual component.
The _owner field is unnecessary since it's reachable from _currentElement.
The _lifeCycle field is unnecessary because an internal component should
not even need to exist at all if it's unmounted. It should be dereferenced
internally, and never exposed externally.
The only case where it's important is for batching updates where we
currently avoid calling performUpdateIfNecessary if it's mounted. However,
this function is already only executed "if necessary" so we just make sure
that it's not necessary after unmount by resetting all the pending fields.
...unless they already have a wrapper. Also, add tagName to every wrapper.
This ensures that refs are consistent. They always look like composite
components. This effectively hides the internal implementation details of
real DOM components since you can no longer get a ref to one.
In the future we might want to drop this wrapper and have refs refer
directly to the DOM node.
I currently use a hacky way of auto-wrapping inside of ReactNativeComponent
so that any given string can be wrapped. Better suggestions are welcome.
Fixes#2493, also closes#2353 as it incorporates a variant of that fix.
- Instead of having getEmptyComponent return `<noscript />` directly, wrap it in a class that we can easily identify later as being an empty component
- Cache the empty component element instead of recreating one each time
- Avoid touching the nullComponentIdsRegistry dictionary at all when not dealing with empty components
- Move empty-component tests to a separate file
Test Plan: jest
ReactTextComponent's implementation is DOM-specific; instead of flattenChildren creating the ReactTextComponent instances, ReactNativeComponent now takes care of having ReactTextComponent injected and creating the component instance. I also renamed ReactTextComponent to ReactDOMTextComponent and moved it to browser/ui/ where it belongs. ReactDOMTextComponent no longer inherits directly from ReactComponent and instead implements construct and {mount,receive,unmount}Component directly.
This diff removes `ReactTestUtils.isTextComponent` which should have previously never returned true when using public APIs.
Test Plan: jest, use ballmer-peak example.
ReactClass is now composed by ReactCompositeComponent rather than
inherit from it.
The state transition functions currently use ReactInstanceMap to map an
instance back to an internal representation.
I updated some tests to use public APIs. Other unit tests still reach into
internals but now we can find them using ReactInstanceMap.
I will do more cleanup in follow ups. The purpose of this diff is to
preserve semantics and most of the existing code.
This effectively enables support for ES6 classes. All you would need to
expose is ReactClassMixin.
Classes are now pure classes without a legacy factory around them.
Since classes will become just any function that returns a valid instance,
let's drop isValidClass.
There's some hacks in here for auto-mocking frameworks (jest) that mock the
prototype of these classes. These hacks allow these classes to be mounted.
Because the JS community's polyfilling infrastructure sucks and we'll
have to fix it for them before we require this.
JSX spread uses React.__spread
(which might get special behavior for key/ref, not sure yet)
This never uses the native implementation and throws for prototype chains.
Once the native implementations are faster, we'll start using them.
This makes it easier to contribute without having to learn a bunch of
slightly different helpers and remember their slightly different
signatures and semantics.
We'll probably start using ES7 spread properties instead of merge in the
future when at least one more transpiler supports it.
React.DOM is becoming helper factories to generate ReactElements. They're not
classes. It will be ok to call them directly as functions, but not to use them
where a class is expected.
I grepped for uses of React.DOM. This is going to be a set of helper functions
to generate ReactElements without JSX.
They're not classes so they cannot be used where a React class is expected.
Since we always use JSX, we should have no internal use for these helpers.
We can use strings instead.
This makes ReactDOM a simple helper for creating ReactElements with the string tag as the type. The actual class is internal and created by instantiateReactComponent. Configurable using injection.
There's not a separate class for each tag. There's just a generic ReactDOMComponent which could take any tag name.
Invididual tags can be wrapped. When wrapping happens you can return the same tag again. If the wrapper returns the same string, then we fall back to the generic component. This avoids recursion in a single level wrapper.
Replace plain function calls to legacy factories with createFactory or
createElement. For ReactDOMComponents the type should be replaced with
strings.
Because we don't have easy access to ReactLegacyDescriptor from within
React, we need to use the .type property to extract the real class.
This will go away later and is covered by unit tests.
This moves all logic around legacy descriptors to ReactLegacyDescriptor. This
is responsible for the layer that knows that createClass exports a legacy
factory. When passed one of these classes, it unwraps it to be a real class.
If it is passed a non legacy factory, it is assumed to be a non-react component
that needs to be invoked as a plain function.
The semantic change is that a descriptor is now always returned if passed a
legacy factory. Even if that factory is a mock. A mock would previously return
undefined.
For mocks, I treat the factory as the authoritative function. I call it to extract
the instance or fill it with an empty component placeholder.
Additionally, I make the classes take props as the first argument to the
constructor. This is what the new class system will do.
We currently need to set up some internals by calling the internal construct
method. Instead of doing that automatically in the constructor, I now move that
to a second pass so that mocks can get the plain props.
This means that we can assert that a mock has been called once it's mounted
with it's final props. Instead of the descriptor factory being called.
The `mockTagName` parameter was always optional, and so probably was not
used very often. If you tried to use it, it would be shadowed by the
`var mockTagName` declaration in the `render` method, so only
`module.mockTagName` or `"div"` were ever possible values.
Currently require('ReactDefaultPerf').printExclusive() shows render
time and aggregate componentMount time.
This makes it show exclusive mount time by tracking a stack.
React components have _mountIndex, that looks like it is their order in DOM.
If you swap 2 elements in DOM, their order in children array isn't changed, but their _mountIndex is
Most of the time this is what you want to do, so I've renamed what was Simulate to be SimulateNative.
Now Simulate.change does what you expect, so this fixes#517 and fixes#519.
grep -rl 'Copyright 2013 Facebook' static_upstream | xargs perl -pi -w -e s/Copyright 2013 Facebook/Copyright 2013-2014 Facebook/g;'
Not going to check in a script to do this since it will just change every year.
Closes#1006
ReactDefaultPerf:
* Show times as float instead of string. This means they're sortable.
* Add count columns to all types and average to exclusive time.
* Include mountComponent where updateComponent time is measured.
* Increment count on _renderValidatedComponent instead of update.
ReactDefaultPerfAnalysis:
* Return counts with all summaries.