Skip to content

Commit 6ea6edc

Browse files
authored
New commit phase lifecycle: getSnapshotBeforeUpdate (#12404)
* Implemented new getSnapshotBeforeUpdate lifecycle * Store snapshot value from Fiber to instance (__reactInternalSnapshotBeforeUpdate) * Use commitAllHostEffects() traversal for getSnapshotBeforeUpdate() * Added DEV warnings and tests for new lifecycle * Don't invoke legacy lifecycles if getSnapshotBeforeUpdate() is defined. DEV warn about this. * Converted did-warn objects to Sets in ReactFiberClassComponent * Replaced redundant new lifecycle checks in a few methods * Check for polyfill suppress flag on cWU as well before warning * Added Snapshot bit to HostEffectMask
1 parent 84d5838 commit 6ea6edc

File tree

2 files changed

+74
-36
lines changed

2 files changed

+74
-36
lines changed

src/ReactShallowRenderer.js

+32-36
Original file line numberDiff line numberDiff line change
@@ -139,20 +139,18 @@ class ReactShallowRenderer {
139139
) {
140140
const beforeState = this._newState;
141141

142-
if (typeof this._instance.componentWillMount === 'function') {
143-
// In order to support react-lifecycles-compat polyfilled components,
144-
// Unsafe lifecycles should not be invoked for any component with the new gDSFP.
145-
if (typeof element.type.getDerivedStateFromProps !== 'function') {
146-
this._instance.componentWillMount();
147-
}
148-
}
142+
// In order to support react-lifecycles-compat polyfilled components,
143+
// Unsafe lifecycles should not be invoked for components using the new APIs.
149144
if (
150-
typeof this._instance.UNSAFE_componentWillMount === 'function' &&
151-
typeof element.type.getDerivedStateFromProps !== 'function'
145+
typeof element.type.getDerivedStateFromProps !== 'function' &&
146+
typeof this._instance.getSnapshotBeforeUpdate !== 'function'
152147
) {
153-
// In order to support react-lifecycles-compat polyfilled components,
154-
// Unsafe lifecycles should not be invoked for any component with the new gDSFP.
155-
this._instance.UNSAFE_componentWillMount();
148+
if (typeof this._instance.componentWillMount === 'function') {
149+
this._instance.componentWillMount();
150+
}
151+
if (typeof this._instance.UNSAFE_componentWillMount === 'function') {
152+
this._instance.UNSAFE_componentWillMount();
153+
}
156154
}
157155

158156
// setState may have been called during cWM
@@ -173,20 +171,20 @@ class ReactShallowRenderer {
173171
const oldProps = this._instance.props;
174172

175173
if (oldProps !== props) {
176-
if (typeof this._instance.componentWillReceiveProps === 'function') {
177-
// In order to support react-lifecycles-compat polyfilled components,
178-
// Unsafe lifecycles should not be invoked for any component with the new gDSFP.
179-
if (typeof element.type.getDerivedStateFromProps !== 'function') {
180-
this._instance.componentWillReceiveProps(props, context);
181-
}
182-
}
174+
// In order to support react-lifecycles-compat polyfilled components,
175+
// Unsafe lifecycles should not be invoked for components using the new APIs.
183176
if (
184-
typeof this._instance.UNSAFE_componentWillReceiveProps === 'function' &&
185-
typeof element.type.getDerivedStateFromProps !== 'function'
177+
typeof element.type.getDerivedStateFromProps !== 'function' &&
178+
typeof this._instance.getSnapshotBeforeUpdate !== 'function'
186179
) {
187-
// In order to support react-lifecycles-compat polyfilled components,
188-
// Unsafe lifecycles should not be invoked for any component with the new gDSFP.
189-
this._instance.UNSAFE_componentWillReceiveProps(props, context);
180+
if (typeof this._instance.componentWillReceiveProps === 'function') {
181+
this._instance.componentWillReceiveProps(props, context);
182+
}
183+
if (
184+
typeof this._instance.UNSAFE_componentWillReceiveProps === 'function'
185+
) {
186+
this._instance.UNSAFE_componentWillReceiveProps(props, context);
187+
}
190188
}
191189

192190
this._updateStateFromStaticLifecycle(props);
@@ -211,20 +209,18 @@ class ReactShallowRenderer {
211209
}
212210

213211
if (shouldUpdate) {
214-
if (typeof this._instance.componentWillUpdate === 'function') {
215-
// In order to support react-lifecycles-compat polyfilled components,
216-
// Unsafe lifecycles should not be invoked for any component with the new gDSFP.
217-
if (typeof type.getDerivedStateFromProps !== 'function') {
218-
this._instance.componentWillUpdate(props, state, context);
219-
}
220-
}
212+
// In order to support react-lifecycles-compat polyfilled components,
213+
// Unsafe lifecycles should not be invoked for components using the new APIs.
221214
if (
222-
typeof this._instance.UNSAFE_componentWillUpdate === 'function' &&
223-
typeof type.getDerivedStateFromProps !== 'function'
215+
typeof element.type.getDerivedStateFromProps !== 'function' &&
216+
typeof this._instance.getSnapshotBeforeUpdate !== 'function'
224217
) {
225-
// In order to support react-lifecycles-compat polyfilled components,
226-
// Unsafe lifecycles should not be invoked for any component with the new gDSFP.
227-
this._instance.UNSAFE_componentWillUpdate(props, state, context);
218+
if (typeof this._instance.componentWillUpdate === 'function') {
219+
this._instance.componentWillUpdate(props, state, context);
220+
}
221+
if (typeof this._instance.UNSAFE_componentWillUpdate === 'function') {
222+
this._instance.UNSAFE_componentWillUpdate(props, state, context);
223+
}
228224
}
229225
}
230226

src/__tests__/ReactShallowRenderer-test.js

+42
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,48 @@ describe('ReactShallowRenderer', () => {
128128
shallowRenderer.render(<Component />);
129129
});
130130

131+
it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new getSnapshotBeforeUpdate is present', () => {
132+
class Component extends React.Component {
133+
getSnapshotBeforeUpdate() {
134+
return null;
135+
}
136+
componentWillMount() {
137+
throw Error('unexpected');
138+
}
139+
componentWillReceiveProps() {
140+
throw Error('unexpected');
141+
}
142+
componentWillUpdate() {
143+
throw Error('unexpected');
144+
}
145+
render() {
146+
return null;
147+
}
148+
}
149+
150+
const shallowRenderer = createRenderer();
151+
shallowRenderer.render(<Component value={1} />);
152+
shallowRenderer.render(<Component value={2} />);
153+
});
154+
155+
it('should not call getSnapshotBeforeUpdate or componentDidUpdate when updating since refs wont exist', () => {
156+
class Component extends React.Component {
157+
getSnapshotBeforeUpdate() {
158+
throw Error('unexpected');
159+
}
160+
componentDidUpdate() {
161+
throw Error('unexpected');
162+
}
163+
render() {
164+
return null;
165+
}
166+
}
167+
168+
const shallowRenderer = createRenderer();
169+
shallowRenderer.render(<Component value={1} />);
170+
shallowRenderer.render(<Component value={2} />);
171+
});
172+
131173
it('should only render 1 level deep', () => {
132174
function Parent() {
133175
return (

0 commit comments

Comments
 (0)