Fixes#3473
I tag each React element with `$$typeof: Symbol.for('react.element')`. We need
this to be able to safely distinguish these from plain objects that might have
come from user provided JSON.
The idiomatic JavaScript way of tagging an object is for it to inherent some
prototype and then use `instanceof` to test for it.
However, this has limitations since it doesn't work with value types which
require `typeof` checks. They also don't work across realms. Which is why there
are alternative tag checks like `Array.isArray` or the `toStringTag`. Another
problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot.
Additionally, it is our hope that ReactElement will one day be specified in
terms of a "Value Type" style record instead of a plain Object.
This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements:
https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator
Additionally, there is already a system for coordinating tags across module
systems and even realms in ES6. Namely using `Symbol.for`.
Currently these objects are not able to transfer between Workers but there is
nothing preventing that from being possible in the future. You could imagine
even `Symbol.for` working across Worker boundaries. You could also build a
system that coordinates Symbols and Value Types from server to client or through
serialized forms. That's beyond the scope of React itself, and if it was built
it seems like it would belong with the `Symbol` system. A system could override
the `Symbol.for('react.element')` to return a plain yet
cryptographically random or unique number. That would allow ReactElements to
pass through JSON without risking the XSS issue.
The fallback solution is a plain well-known number. This makes it unsafe with
regard to the XSS issue described in #3473. We could have used a much more
convoluted solution to protect against JSON specifically but that would require
some kind of significant coordination, or change the check to do a
`typeof element.$$typeof === 'function'` check which would not make it unique to
React. It seems cleaner to just use a fixed number since the protection is just
a secondary layer anyway. I'm not sure if this is the right tradeoff.
In short, if you want the XSS protection, use a proper Symbol polyfill.
Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type`
and the use case is to add a tag that the `typeof` operator would refer to.
I would use `@@typeof` but that seems to deopt in JSC. I also don't use
`__typeof` because this is more than a framework private. It should really be
part of the polyfilling layer.
As of this commit, we still support objects as maps so if anyone has an object with keys 'type' and 'props' this will change behavior, but otherwise this should be pretty safe.
This is a machine-generated codemod, but it's pretty safe since it was
generated by hooking into eslint's own report.
A few files had to be touched up by hand because there were existing
formatting issues with nested arrays/objects:
src/shared/utils/__tests__/OrderedMap-test.js
src/shared/utils/__tests__/Transaction-test.js
src/shared/utils/__tests__/traverseAllChildren-test.js
src/isomorphic/children/__tests__/ReactChildren-test.js
This heuristic isn't great because it relies on inspecting deep children which aren't guaranteed to be React elements. In particular, this was causing stack overflows in a component we had that used a *DOM node* as children, like `<DOMContainer>{node}</DOMContainer>`.
This reverts commits:
0a3aa8493a64c9d9d7620c58f4f6b18cf226e442086636747f
The new folder structure is organized around major packages that are expected to ship separately in some form.
`/isomorphic`
I moved classic/modern and children utils into a directory called "isomorphic" with the main export being ReactIsomorphic. This will eventually become the "react" package.
This includes all the dependencies that you might need to create a component without dependencies on the renderer/reconciler.
The rest moves into decoupled renderers.
`/renderers/dom/client` - This is the main renderer for DOM.
`/renderers/dom/server` - This is the server-side renderer for HTML strings.
`/addons` and `/test` - Same as before for now.
You're not supposed to take on a dependency inside another package.
Shared code is organized into a "shared" directory which is intended to support all the packages in that subdirectory. Meaning that once we swap to CommonJS modules, the only time you should use `..` is to target `../shared/` or `../../shared`.
E.g. `/shared/` is common utils that are used by everything.
`/renderers/shared/` is code that is shared by all renderers, such as the main reconciliation algorithm.
Shared code will likely be copied into each package rather than referenced. This allow us to have separate state and allow inlining and deadcode elimination.