Skip to content
This repository was archived by the owner on Apr 9, 2019. It is now read-only.

Commit 6dd0ae8

Browse files
committed
Merge branch 'lifecycle-events'
2 parents e22b728 + 99e1453 commit 6dd0ae8

File tree

3 files changed

+153
-23
lines changed

3 files changed

+153
-23
lines changed

README.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
React view manager similar to [UINavigationController][ios-controller]
77

8-
## Instalation
8+
## Installation
99

1010
```bash
1111
npm install react-navigation-controller
@@ -194,6 +194,46 @@ If set to `true`, the navigationController will save the state
194194
of each view that gets pushed onto the stack. When `popView()` is called,
195195
the navigationController will rehydrate the state of the view before it is shown.
196196

197+
## Lifecycle Events
198+
199+
Similar to the React component lifecycle, the navigationController will
200+
call lifecycle events on the component at certain stages.
201+
202+
Lifecycle events can trigger actions when views transition in or out,
203+
instead of mounted or unmounted:
204+
205+
```
206+
class HelloView extends React.Component {
207+
navigationControllerDidShowView() {
208+
// Do something when the show transition is finished,
209+
// like fade in an element.
210+
}
211+
navigationControllerWillHideView() {
212+
// Do something when the hide transition will start,
213+
// like fade out an element.
214+
}
215+
render() {
216+
return <div>Hello, {this.props.name}!</div>;
217+
}
218+
}
219+
```
220+
221+
### `view.navigationControllerWillHideView()`
222+
223+
Invoked immediately before the previous view will be hidden.
224+
225+
### `view.navigationControllerWillShowView()`
226+
227+
Invoked immediately before the next view will be shown.
228+
229+
### `view.navigationControllerDidHideView()`
230+
231+
Invoked immediately after the previous view has been hidden.
232+
233+
### `view.navigationControllerDidShowView()`
234+
235+
Invoked immediately after the next view has been shown.
236+
197237
## Styling
198238

199239
No default styles are provided, but classes are added for custom styling:

examples/src/view.jsx

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,6 @@ class View extends React.Component {
3131
counter: this.state.counter + 1
3232
});
3333
}
34-
componentDidMount() {
35-
console.log('component did mount', this.props.index);
36-
}
37-
navigationControllerWillShowView() {
38-
console.log('will show view', this.props.index);
39-
}
40-
navigationControllerDidShowView() {
41-
console.log('did show view', this.props.index);
42-
}
43-
navigationControllerWillHideView() {
44-
console.log('will hide view', this.props.index);
45-
}
46-
navigationControllerDidHideView() {
47-
console.log('did hide view', this.props.index);
48-
}
49-
componentWillUnmount() {
50-
console.log('component will unmount', this.props.index);
51-
}
5234
onNext() {
5335
const view = <View index={this.props.index+1} />;
5436
this.props.navigationController.pushView(view, {

spec/navigation-controller.spec.jsx

Lines changed: 112 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe('NavigationController', () => {
3333
);
3434
viewWrapper0 = controller['__view-wrapper-0'];
3535
viewWrapper1 = controller['__view-wrapper-1'];
36-
})
36+
});
3737
it('exports a component', () => {
3838
let controller = renderIntoDocument(
3939
<NavigationController views={views} />
@@ -86,9 +86,6 @@ describe('NavigationController', () => {
8686
expect(viewWrapper0).to.have.deep.property(`style.${transformPrefix}`);
8787
expect(viewWrapper1).to.have.deep.property(`style.${transformPrefix}`);
8888
});
89-
});
90-
describe('#componentWillUnmout', () => {
91-
9289
});
9390
describe('#__transformViews', () => {
9491
beforeEach(done => {
@@ -808,4 +805,115 @@ describe('NavigationController', () => {
808805
});
809806
});
810807
});
808+
describe('Lifecycle Events', () => {
809+
let stubLifecycleEvents = (onTransitionViews) => {
810+
const e = {
811+
prevView: {
812+
willHide: sinon.spy(),
813+
didHide: sinon.spy()
814+
},
815+
nextView: {
816+
willShow: sinon.spy(),
817+
didShow: sinon.spy()
818+
}
819+
}
820+
const stub = sinon.stub(controller, '__transitionViews', (options) => {
821+
let prevView = controller.refs['view-0'];
822+
if (prevView) {
823+
prevView.navigationControllerWillHideView = e.prevView.willHide;
824+
prevView.navigationControllerDidHideView = e.prevView.didHide;
825+
}
826+
let nextView = controller.refs['view-1'];
827+
if (nextView) {
828+
nextView.navigationControllerWillShowView = e.nextView.willShow;
829+
nextView.navigationControllerDidShowView = e.nextView.didShow;
830+
}
831+
stub.restore();
832+
controller.__transitionViews(options);
833+
onTransitionViews();
834+
});
835+
return e;
836+
};
837+
describe('#__pushView', () => {
838+
beforeEach(done => {
839+
requestAnimationFrame(() => {
840+
done();
841+
});
842+
});
843+
it('calls events with a "none" transition', (done) => {
844+
const e = stubLifecycleEvents(() => {
845+
expect(e.prevView.willHide.calledOnce).to.be.true;
846+
expect(e.nextView.willShow.calledOnce).to.be.true;
847+
expect(e.prevView.didHide.calledOnce).to.be.false;
848+
expect(e.nextView.didShow.calledOnce).to.be.false;
849+
});
850+
controller.__pushView(<ViewB />, {
851+
transition: Transition.type.NONE,
852+
onComplete() {
853+
expect(e.prevView.didHide.calledOnce).to.be.true;
854+
expect(e.nextView.didShow.calledOnce).to.be.true;
855+
done();
856+
}
857+
});
858+
});
859+
it('calls events with a built-in spring animation', (done) => {
860+
const e = stubLifecycleEvents(() => {
861+
expect(e.prevView.willHide.calledOnce).to.be.true;
862+
expect(e.nextView.willShow.calledOnce).to.be.true;
863+
expect(e.prevView.didHide.calledOnce).to.be.false;
864+
expect(e.nextView.didShow.calledOnce).to.be.false;
865+
});
866+
controller.__pushView(<ViewB />, {
867+
transition: Transition.type.PUSH_LEFT,
868+
onComplete() {
869+
expect(e.prevView.didHide.calledOnce).to.be.true;
870+
expect(e.nextView.didShow.calledOnce).to.be.true;
871+
done();
872+
}
873+
});
874+
});
875+
});
876+
describe('#__popView', () => {
877+
beforeEach(done => {
878+
controller = renderIntoDocument(
879+
<NavigationController views={[<ViewA />,<ViewB />]} />
880+
);
881+
requestAnimationFrame(() => {
882+
done();
883+
});
884+
});
885+
it('calls events with a "none" transition', (done) => {
886+
const e = stubLifecycleEvents(() => {
887+
expect(e.prevView.willHide.calledOnce).to.be.true;
888+
expect(e.nextView.willShow.calledOnce).to.be.true;
889+
expect(e.prevView.didHide.calledOnce).to.be.false;
890+
expect(e.nextView.didShow.calledOnce).to.be.false;
891+
});
892+
controller.__popView({
893+
transition: Transition.type.NONE,
894+
onComplete() {
895+
expect(e.prevView.didHide.calledOnce).to.be.true;
896+
expect(e.nextView.didShow.calledOnce).to.be.true;
897+
done();
898+
}
899+
});
900+
});
901+
it('calls events with a built-in spring animation', (done) => {
902+
const e = stubLifecycleEvents(() => {
903+
expect(e.prevView.willHide.calledOnce).to.be.true;
904+
expect(e.nextView.willShow.calledOnce).to.be.true;
905+
expect(e.prevView.didHide.calledOnce).to.be.false;
906+
expect(e.nextView.didShow.calledOnce).to.be.false;
907+
});
908+
controller.__popView({
909+
transition: Transition.type.PUSH_LEFT,
910+
onComplete() {
911+
expect(e.prevView.didHide.calledOnce).to.be.true;
912+
expect(e.nextView.didShow.calledOnce).to.be.true;
913+
done();
914+
}
915+
});
916+
});
917+
});
918+
});
811919
});

0 commit comments

Comments
 (0)