Skip to content

Commit 4f64cc2

Browse files
author
Keyan Zhang
committed
defer state property initializer evaluation when necessary
1 parent 59e3671 commit 4f64cc2

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

transforms/__testfixtures__/class-initial-state.input.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,18 @@ var Loader = React.createClass({
129129
},
130130
});
131131

132+
var DeferStateInitialization = React.createClass({
133+
getInitialState() {
134+
return {x: this.something};
135+
},
136+
137+
something: 42,
138+
139+
render() {
140+
return <div onClick={this.reset} />;
141+
},
142+
});
143+
132144
var helper = () => {};
133145

134146
var PassGetInitialState = React.createClass({

transforms/__testfixtures__/class-initial-state.output.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,13 @@ class MyComponent3 extends React.Component {
105105
}
106106

107107
class MyComponent4 extends React.Component {
108-
state = {
109-
heyoo: getContextFromInstance(this),
110-
};
111-
112108
foo = (): void => {
113109
this.setState({heyoo: 24});
114110
};
111+
112+
state = {
113+
heyoo: getContextFromInstance(this),
114+
};
115115
}
116116

117117
class Loader extends React.Component {
@@ -141,6 +141,15 @@ class Loader extends React.Component {
141141
}
142142
}
143143

144+
class DeferStateInitialization extends React.Component {
145+
something = 42;
146+
state = {x: this.something};
147+
148+
render() {
149+
return <div onClick={this.reset} />;
150+
}
151+
}
152+
144153
var helper = () => {};
145154

146155
var PassGetInitialState = React.createClass({

transforms/class.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,23 @@ module.exports = (file, api, options) => {
645645
);
646646
};
647647

648+
// to ensure that our property initializers' evaluation order is safe
649+
const repositionStateProperty = (initialStateProperty, propertiesAndMethods) => {
650+
if (j(initialStateProperty).find(j.ThisExpression).size() === 0) {
651+
return initialStateProperty.concat(propertiesAndMethods);
652+
}
653+
654+
const result = [].concat(propertiesAndMethods);
655+
let lastPropPosition = result.length - 1;
656+
657+
while (lastPropPosition >= 0 && result[lastPropPosition].kind === 'method') {
658+
lastPropPosition--;
659+
}
660+
661+
result.splice(lastPropPosition + 1, 0, initialStateProperty[0]);
662+
return result;
663+
};
664+
648665
// if there's no `getInitialState` or the `getInitialState` function is simple
649666
// (i.e., it's just a return statement) then we don't need a constructor.
650667
// we can simply lift `state = {...}` as a property initializer.
@@ -706,8 +723,7 @@ module.exports = (file, api, options) => {
706723
flowPropsAnnotation,
707724
staticProperties,
708725
maybeConstructor,
709-
initialStateProperty,
710-
propertiesAndMethods
726+
repositionStateProperty(initialStateProperty, propertiesAndMethods)
711727
)
712728
),
713729
j.memberExpression(

0 commit comments

Comments
 (0)