Support multiple actions in one tick and fire them in the order that they arrive

This commit is contained in:
Brent Vatne
2018-09-26 16:50:21 -07:00
parent 6995754f96
commit 3eca8faa0f
5 changed files with 65 additions and 39 deletions

View File

@@ -24,7 +24,6 @@ class Home extends React.Component {
_renderItem = ({ item }) => (
<List.Item
title={item.title}
style={{ backgroundColor: '#fff' }}
onPress={() => this.props.navigation.navigate(item.routeName)}
/>
);
@@ -37,6 +36,7 @@ class Home extends React.Component {
ItemSeparatorComponent={Divider}
renderItem={this._renderItem}
keyExtractor={this._keyExtractor}
style={{ backgroundColor: '#fff' }}
data={data}
/>
);

View File

@@ -15,12 +15,26 @@ const MyNavScreen = ({ navigation, banner }) => (
</View>
<Button onPress={() => navigation.openDrawer()} title="Open drawer" />
<Button onPress={() => navigation.toggleDrawer()} title="Toggle drawer" />
<Button
onPress={() => {
navigation.openDrawer();
navigation.closeDrawer();
}}
title="Open and immediately close"
/>
<Button
onPress={() => {
navigation.closeDrawer();
navigation.openDrawer();
}}
title="Close and immediately open"
/>
<Button
onPress={() => {
navigation.openDrawer();
setTimeout(() => {
navigation.closeDrawer();
}, 500);
}, 150);
}}
title="Open then close drawer shortly after"
/>

View File

@@ -24,6 +24,12 @@ export default (routeConfigs, config = {}) => {
const switchRouter = SwitchRouter(routeConfigs, config);
let __id = -1;
const genId = () => {
__id++;
return __id;
};
return {
...switchRouter,
@@ -42,9 +48,9 @@ export default (routeConfigs, config = {}) => {
return {
...switchRouter.getStateForAction(action, undefined),
isDrawerOpen: false,
openId: 0,
closeId: 0,
toggleId: 0,
openId: genId(),
closeId: genId(),
toggleId: genId(),
};
}
@@ -70,28 +76,28 @@ export default (routeConfigs, config = {}) => {
if (action.type === DrawerActions.CLOSE_DRAWER) {
return {
...state,
closeId: state.closeId + 1,
closeId: genId(),
};
}
if (action.type === NavigationActions.BACK && state.isDrawerOpen) {
return {
...state,
closeId: state.closeId + 1,
closeId: genId(),
};
}
if (action.type === DrawerActions.OPEN_DRAWER) {
return {
...state,
openId: state.openId + 1,
openId: genId(),
};
}
if (action.type === DrawerActions.TOGGLE_DRAWER) {
return {
...state,
toggleId: state.toggleId + 1,
toggleId: genId(),
};
}
}
@@ -110,7 +116,7 @@ export default (routeConfigs, config = {}) => {
// If any navigation has happened, make sure to close the drawer
return {
...switchedState,
closeId: state.closeId + 1,
closeId: genId(),
};
}

View File

@@ -26,8 +26,8 @@ describe('DrawerRouter', () => {
],
isDrawerOpen: false,
openId: 0,
closeId: 0,
toggleId: 0,
closeId: 1,
toggleId: 2,
};
expect(state).toEqual(expectedState);
const state2 = router.getStateForAction(
@@ -43,8 +43,8 @@ describe('DrawerRouter', () => {
],
isDrawerOpen: false,
openId: 0,
closeId: 1,
toggleId: 0,
closeId: 3,
toggleId: 2,
};
expect(state2).toEqual(expectedState2);
expect(router.getComponentForState(expectedState)).toEqual(ScreenA);
@@ -74,8 +74,8 @@ describe('DrawerRouter', () => {
isDrawerOpen: false,
isTransitioning: false,
openId: 0,
closeId: 0,
toggleId: 0,
closeId: 1,
toggleId: 2,
routes: [
{
key: 'Foo',
@@ -99,22 +99,22 @@ describe('DrawerRouter', () => {
Bar: { screen: ScreenB },
});
const state = router.getStateForAction(INIT_ACTION);
expect(state.toggleId).toEqual(0);
expect(state.toggleId).toEqual(2);
const state2 = router.getStateForAction(
{ type: DrawerActions.OPEN_DRAWER },
state
);
expect(state2.openId).toEqual(1);
expect(state2.openId).toEqual(3);
const state3 = router.getStateForAction(
{ type: DrawerActions.CLOSE_DRAWER },
state2
);
expect(state3.closeId).toEqual(1);
expect(state3.closeId).toEqual(4);
const state4 = router.getStateForAction(
{ type: DrawerActions.TOGGLE_DRAWER },
state3
);
expect(state4.toggleId).toEqual(1);
expect(state4.toggleId).toEqual(5);
});
test('Drawer opens closes with key targeted', () => {
@@ -134,7 +134,7 @@ describe('DrawerRouter', () => {
{ type: DrawerActions.OPEN_DRAWER, key: state.key },
state2
);
expect(state3.openId).toEqual(1);
expect(state3.openId).toEqual(3);
});
});
@@ -171,10 +171,10 @@ test('Drawer does not fire close when child routers return new state', () => {
});
const state = router.getStateForAction(INIT_ACTION);
expect(state.closeId).toEqual(0);
expect(state.closeId).toEqual(1);
const state2 = router.getStateForAction({ type: 'CHILD_ACTION' }, state2);
expect(state2.closeId).toEqual(0);
const state2 = router.getStateForAction({ type: 'CHILD_ACTION' }, state);
expect(state2.closeId).toEqual(1);
expect(state2.routes[0].changed).toEqual(true);
});
@@ -204,13 +204,13 @@ test('DrawerRouter will close drawer on child navigaton, not on child param chan
DrawerActions.openDrawer(),
emptyState
);
expect(initState.openId).toBe(1);
expect(initState.openId).toBe(3);
const state0 = router.getStateForAction(
NavigationActions.navigate({ routeName: 'Quo' }),
initState
);
expect(state0.closeId).toBe(1);
expect(state0.closeId).toBe(4);
const initSwitchState = initState.routes[initState.index];
const initQuxState = initSwitchState.routes[initSwitchState.index];
@@ -224,7 +224,7 @@ test('DrawerRouter will close drawer on child navigaton, not on child param chan
);
const state1switchState = state1.routes[state1.index];
const state1quxState = state1switchState.routes[state1switchState.index];
expect(state1.closeId).toBe(0); // don't fire close
expect(state1.closeId).toBe(1); // don't fire close
expect(state1quxState.params.foo).toEqual('bar');
});
@@ -253,10 +253,9 @@ test('goBack closes drawer when inside of stack', () => {
);
expect(state3.index).toEqual(1);
expect(state3.routes[1].isDrawerOpen).toEqual(true);
expect(state3.routes[1].closeId).toEqual(0);
expect(state3.routes[1].closeId).toEqual(1); // changed
const state4 = router.getStateForAction(NavigationActions.back(), state3);
expect(state4.index).toEqual(1);
expect(state4.routes[1].closeId).toEqual(1);
expect(state4.routes[1].closeId).toEqual(4);
const state5 = router.getStateForAction(
{ type: DrawerActions.DRAWER_CLOSED },
state4

View File

@@ -33,17 +33,24 @@ export default class DrawerView extends React.PureComponent {
toggleId: prevToggleId,
} = prevProps.navigation.state;
if (openId !== prevOpenId) {
this._drawer.openDrawer();
} else if (closeId !== prevCloseId) {
this._drawer.closeDrawer();
} else if (toggleId !== prevToggleId) {
if (isDrawerOpen) {
this._drawer.closeDrawer();
} else {
let prevIds = [prevOpenId, prevCloseId, prevToggleId];
let changedIds = [openId, closeId, toggleId]
.filter(id => !prevIds.includes(id))
.sort((a, b) => a > b);
changedIds.forEach(id => {
if (id === openId) {
this._drawer.openDrawer();
} else if (id === closeId) {
this._drawer.closeDrawer();
} else if (id === toggleId) {
if (isDrawerOpen) {
this._drawer.closeDrawer();
} else {
this._drawer.openDrawer();
}
}
}
});
}
componentWillUnmount() {