Skip to content

Commit 3b75b8b

Browse files
author
徐远翔
committed
feat: 双向同步history、navigation状态,支持使用 history 或者 navigation 进行命令式跳转。
1 parent d33de18 commit 3b75b8b

File tree

7 files changed

+52
-29
lines changed

7 files changed

+52
-29
lines changed

.github/workflows/android.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ on:
1111
jobs:
1212
test-android:
1313
runs-on: macos-latest
14-
defaults:
15-
run:
16-
shell: bash
17-
working-directory: example
1814
steps:
1915
- uses: actions/checkout@v2
2016
- name: Setup sdk
@@ -42,6 +38,10 @@ jobs:
4238
node-version: '10.x'
4339
- name: Install npm denpendencies
4440
run: yarn install --frozen-lockfile --non-interactive --silent
41+
- name: Compilation
42+
run: yarn build
43+
- name: Install example npm denpendencies
44+
run: cd example && yarn install --frozen-lockfile --non-interactive --silent
4545
- name: Generate umi temp files
4646
run: yarn generate
4747
- name: Show details

.github/workflows/ios.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,17 @@ on:
1111
jobs:
1212
test-ios:
1313
runs-on: macos-latest
14-
defaults:
15-
run:
16-
shell: bash
17-
working-directory: example
1814
steps:
1915
- uses: actions/checkout@v2
2016
- uses: actions/setup-node@v1
2117
with:
2218
node-version: '10.x'
2319
- name: Install npm denpendencies
2420
run: yarn install --frozen-lockfile --non-interactive --silent
21+
- name: Compilation
22+
run: yarn build
23+
- name: Install example npm denpendencies
24+
run: cd example && yarn install --frozen-lockfile --non-interactive --silent
2525
- name: Install pod denpendencies
2626
run: cd ios && pod install --silent && cd -
2727
- name: Build ios

docs/Router.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ export function getReactNavigationInitialIndicator() {
246246
}
247247

248248
// 订阅 react-navigation 状态变化通知,每次路由变化时,将导航状态持久化保存到手机本地。
249-
export async function onReactNavigationStateChange(state) {
249+
export async function onReactNavigationStateChange({ state }) {
250250
if (state) {
251251
await AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state));
252252
}

example/package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"react-native-gesture-handler": "1.6.1",
2424
"react-native-reanimated": "1.8.0",
2525
"react-native-safe-area-context": "1.0.2",
26-
"react-native-screens": "2.7.0"
26+
"react-native-screens": "2.7.0",
27+
"umi-renderer-react-navigation": "file:../packages/umi-renderer-react-navigation"
2728
},
2829
"devDependencies": {
2930
"@babel/core": "^7.6.2",
@@ -38,8 +39,8 @@
3839
"appium": "^1.17.1",
3940
"metro-react-native-babel-preset": "^0.59.0",
4041
"umi": "^3.2.1",
41-
"umi-preset-react-native": "0.6.0-alpha.0",
42-
"umi-preset-react-navigation": "0.6.0-alpha.0",
42+
"umi-preset-react-native": "file:../packages/umi-preset-react-native",
43+
"umi-preset-react-navigation": "file:../packages/umi-preset-react-navigation",
4344
"webdriverio": "^6.1.14"
4445
}
4546
}

example/pages/index.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { StatusBar, Text, Button } from 'react-native';
33
import { connect, Link } from 'umi';
44
import { getTestProps } from '../services';
55

6-
function IndexPage({ greeting }) {
6+
function IndexPage({ greeting, navigation }) {
77
return (
88
<>
99
<StatusBar barStyle="light-content" />
@@ -14,11 +14,10 @@ function IndexPage({ greeting }) {
1414
component={Button}
1515
title="Go to FeedbackPage"
1616
/>
17-
<Link
17+
<Button
1818
{...getTestProps('linkToLoginPage')}
19-
to="/login"
20-
component={Button}
2119
title="Go to LoginPage"
20+
onPress={() => navigation.navigate('/login')}
2221
/>
2322
</>
2423
);

example/pages/profile/settings/feedback.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export default function FeedBackPage({ route, navigation }) {
88
navigation.setOptions({
99
headerTitle: () => <Text {...getTestProps('feedbackPageTitle')}>Feedback Page</Text>,
1010
headerLeft: ({ label, ...rests }) => (
11-
<Button title={label} {...rests} {...getTestProps('feedbackPageBackButton')} />
11+
<Button title={label || ''} {...rests} {...getTestProps('feedbackPageBackButton')} />
1212
),
1313
}),
1414
[navigation],

packages/umi-renderer-react-navigation/src/createHistoryNavigator.tsx

+35-12
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,16 @@ import {
1515
StackNavigationConfig,
1616
StackNavigationOptions,
1717
} from '@react-navigation/stack/lib/typescript/src/types';
18-
import { History, Location, Action } from 'history';
19-
import { parse } from 'querystring';
18+
import { Location, Action } from 'history';
19+
import { parse, stringify } from 'querystring';
2020

2121
function HistoryNavigator({
2222
initialRouteName,
2323
children,
2424
screenOptions,
2525
history,
2626
...rest
27-
}: DefaultNavigatorOptions<StackNavigationOptions> &
28-
StackRouterOptions &
29-
StackNavigationConfig & { history: History<any> }) {
27+
}: DefaultNavigatorOptions<StackNavigationOptions> & StackRouterOptions & StackNavigationConfig & { history: any }) {
3028
const defaultOptions = {
3129
gestureEnabled: Platform.OS === 'ios',
3230
animationEnabled: Platform.OS !== 'web',
@@ -73,27 +71,52 @@ function HistoryNavigator({
7371
[navigation, state.index, state.key],
7472
);
7573

76-
React.useEffect(
77-
() =>
74+
React.useEffect(() => {
75+
if (history.index > state.index) {
76+
history.go(state.index - history.index);
77+
} else if (history.index < state.index) {
78+
const route = state.routes[state.index];
79+
if (route) {
80+
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
81+
// @ts-ignore
82+
history.push(route.params ? `${route.name}?${stringify(route.params)}` : route.name);
83+
}
84+
}
85+
const subscribes: (() => void)[] = [];
86+
subscribes.push(
7887
history.listen((location: Location<any>, action: Action): void => {
7988
if (state.routeNames.includes(location.pathname)) {
8089
switch (action) {
8190
case 'POP':
82-
if (navigation.canGoBack()) {
91+
if (state.index > history.index) {
8392
navigation.dispatch(StackActions.pop());
8493
}
8594
break;
8695
case 'PUSH':
87-
navigation.dispatch(StackActions.push(location.pathname, parse(location.search.replace('?', ''))));
96+
if (state.index < history.index) {
97+
navigation.dispatch(StackActions.push(location.pathname, parse(location.search.replace('?', ''))));
98+
}
8899
break;
89100
case 'REPLACE':
90-
navigation.dispatch(StackActions.replace(location.pathname, parse(location.search.replace('?', ''))));
101+
if (state.index === history.index) {
102+
navigation.dispatch(StackActions.replace(location.pathname, parse(location.search.replace('?', ''))));
103+
}
91104
break;
92105
}
93106
}
94107
}),
95-
[navigation, history],
96-
);
108+
);
109+
return () => {
110+
for (const fn of subscribes) {
111+
if (typeof fn === 'function') {
112+
try {
113+
fn();
114+
} catch (ignored) {}
115+
}
116+
}
117+
};
118+
}, [navigation, history, state]);
119+
97120
return <StackView {...rest} descriptors={descriptors} state={state} navigation={navigation} />;
98121
}
99122

0 commit comments

Comments
 (0)