feature: Support pure expressions in transform-react-constant-elements (#4812)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
export default function () {
|
||||
export default function ({ types: t }) {
|
||||
const immutabilityVisitor = {
|
||||
enter(path, state) {
|
||||
const stop = () => {
|
||||
@@ -11,15 +11,39 @@ export default function () {
|
||||
return;
|
||||
}
|
||||
|
||||
// Elements with refs are not safe to hoist.
|
||||
if (path.isJSXIdentifier({ name: "ref" }) && path.parentPath.isJSXAttribute({ name: path.node })) {
|
||||
return stop();
|
||||
}
|
||||
|
||||
// Ignore identifiers & JSX expressions.
|
||||
if (path.isJSXIdentifier() || path.isIdentifier() || path.isJSXMemberExpression()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!path.isImmutable()) stop();
|
||||
if (!path.isImmutable()) {
|
||||
// If it's not immutable, it may still be a pure expression, such as string concatenation.
|
||||
// It is still safe to hoist that, so long as its result is immutable.
|
||||
// If not, it is not safe to replace as mutable values (like objects) could be mutated after render.
|
||||
// https://github.com/facebook/react/issues/3226
|
||||
if (path.isPure()) {
|
||||
const expressionResult = path.evaluate();
|
||||
if (expressionResult.confident) {
|
||||
// We know the result; check its mutability.
|
||||
const { value } = expressionResult;
|
||||
const isMutable = (value && typeof value === "object") || (typeof value === "function");
|
||||
if (!isMutable) {
|
||||
// It evaluated to an immutable value, so we can hoist it.
|
||||
return;
|
||||
}
|
||||
} else if (t.isIdentifier(expressionResult.deopt)) {
|
||||
// It's safe to hoist here if the deopt reason is an identifier (e.g. func param).
|
||||
// The hoister will take care of how high up it can be hoisted.
|
||||
return;
|
||||
}
|
||||
}
|
||||
stop();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// https://github.com/facebook/react/issues/3226
|
||||
// Not safe to reuse because it is mutable
|
||||
function render() {
|
||||
return <div style={{ width: 100 }} />;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// https://github.com/facebook/react/issues/3226
|
||||
// Not safe to reuse because it is mutable
|
||||
function render() {
|
||||
return <div style={{ width: 100 }} />;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
function render(offset) {
|
||||
return function () {
|
||||
return <div tabIndex={offset + 1} />;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
function render(offset) {
|
||||
var _ref = <div tabIndex={offset + 1} />;
|
||||
|
||||
return function () {
|
||||
return _ref;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
const OFFSET = 3;
|
||||
|
||||
var Foo = React.createClass({
|
||||
render: function () {
|
||||
return (
|
||||
<div tabIndex={OFFSET + 1} />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
const OFFSET = 3;
|
||||
|
||||
var _ref = <div tabIndex={OFFSET + 1} />;
|
||||
|
||||
var Foo = React.createClass({
|
||||
render: function () {
|
||||
return _ref;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
var Foo = React.createClass({
|
||||
render: function () {
|
||||
return (
|
||||
<div data-text={
|
||||
"Some text, " +
|
||||
"and some more too."
|
||||
} />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
var _ref = <div data-text={"Some text, " + "and some more too."} />;
|
||||
|
||||
var Foo = React.createClass({
|
||||
render: function () {
|
||||
return _ref;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user