Skip to content

Commit 09bd01c

Browse files
committed
Fire componentDidMount/componentDidUpdate life-cycles
These happen in the commit phase *before* the setState callback. Unfortunately, we've lost the previous state at this point since we've already mutated the instance. This needs to be fixed somehow.
1 parent 7732835 commit 09bd01c

File tree

3 files changed

+100
-3
lines changed

3 files changed

+100
-3
lines changed

src/renderers/shared/fiber/ReactFiberCommitWork.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,20 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
213213
function commitWork(current : ?Fiber, finishedWork : Fiber) : void {
214214
switch (finishedWork.tag) {
215215
case ClassComponent: {
216+
const instance = finishedWork.stateNode;
217+
if (!current) {
218+
if (typeof instance.componentDidMount === 'function') {
219+
instance.componentDidMount();
220+
}
221+
} else {
222+
if (typeof instance.componentDidUpdate === 'function') {
223+
const prevProps = current.memoizedProps;
224+
// TODO: This is the new state. We don't currently have the previous
225+
// state anymore.
226+
const prevState = instance.state || null;
227+
instance.componentDidUpdate(prevProps, prevState);
228+
}
229+
}
216230
// Clear updates from current fiber. This must go before the callbacks
217231
// are reset, in case an update is triggered from inside a callback. Is
218232
// this safe? Relies on the assumption that work is only committed if
@@ -225,7 +239,7 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
225239
finishedWork.callbackList = null;
226240
callCallbacks(callbackList, finishedWork.stateNode);
227241
}
228-
// TODO: Fire componentDidMount/componentDidUpdate, update refs
242+
// TODO: Fire update refs
229243
return;
230244
}
231245
case HostContainer: {

src/renderers/shared/fiber/ReactFiberScheduler.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
116116
let effectfulFiber = finishedWork.firstEffect;
117117
while (effectfulFiber) {
118118
switch (effectfulFiber.effectTag) {
119+
// TODO: Should we commit host updates here? Otherwise update to parent
120+
// host components are not visible in life-cycles. Such as when you read
121+
// layout information.
119122
case Placement:
120123
case PlacementAndUpdate:
121124
commitInsertion(effectfulFiber);

src/renderers/shared/fiber/__tests__/ReactIncrementalSideEffects-test.js

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,87 @@ describe('ReactIncrementalSideEffects', () => {
557557

558558
});
559559

560-
// TODO: Test that unmounts and deletions happen in the expected way for
561-
// aborted and resumed render life-cycles.
560+
it('calls componentDidMount/Update after insertion/update', () => {
561+
562+
var ops = [];
563+
564+
class Bar extends React.Component {
565+
componentDidMount() {
566+
ops.push('mount:' + this.props.name);
567+
}
568+
componentDidUpdate() {
569+
ops.push('update:' + this.props.name);
570+
}
571+
render() {
572+
return <span />;
573+
}
574+
}
575+
576+
class Wrapper extends React.Component {
577+
componentDidMount() {
578+
ops.push('mount:wrapper-' + this.props.name);
579+
}
580+
componentDidUpdate() {
581+
ops.push('update:wrapper-' + this.props.name);
582+
}
583+
render() {
584+
return <Bar name={this.props.name} />;
585+
}
586+
}
587+
588+
function Foo(props) {
589+
return (
590+
<div>
591+
<Bar key="a" name="A" />
592+
<Wrapper key="b" name="B" />
593+
<div key="cd">
594+
<Bar name="C" />
595+
<Wrapper name="D" />
596+
</div>
597+
{[
598+
<Bar key="e" name="E" />,
599+
<Bar key="f" name="F" />,
600+
]}
601+
<div>
602+
<Bar key="g" name="G" />
603+
</div>
604+
</div>
605+
);
606+
}
607+
608+
ReactNoop.render(<Foo />);
609+
ReactNoop.flush();
610+
expect(ops).toEqual([
611+
'mount:A',
612+
'mount:B',
613+
'mount:wrapper-B',
614+
'mount:C',
615+
'mount:D',
616+
'mount:wrapper-D',
617+
'mount:E',
618+
'mount:F',
619+
'mount:G',
620+
]);
621+
622+
ops = [];
623+
624+
ReactNoop.render(<Foo />);
625+
ReactNoop.flush();
626+
expect(ops).toEqual([
627+
'update:A',
628+
'update:B',
629+
'update:wrapper-B',
630+
'update:C',
631+
'update:D',
632+
'update:wrapper-D',
633+
'update:E',
634+
'update:F',
635+
'update:G',
636+
]);
637+
638+
});
639+
640+
// TODO: Test that mounts, updates, refs, unmounts and deletions happen in the
641+
// expected way for aborted and resumed render life-cycles.
562642

563643
});

0 commit comments

Comments
 (0)