mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-05-21 15:46:51 +08:00
feat: add an onStateChange prop to NavigationContainer
This commit is contained in:
1
.babelrc
1
.babelrc
@@ -7,6 +7,7 @@
|
||||
"corejs": 3
|
||||
}
|
||||
],
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-typescript"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"@babel/cli": "^7.4.4",
|
||||
"@babel/core": "^7.4.5",
|
||||
"@babel/preset-env": "^7.4.5",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/preset-typescript": "^7.3.3",
|
||||
"@commitlint/config-conventional": "^8.0.0",
|
||||
"@release-it/conventional-changelog": "^1.1.0",
|
||||
@@ -58,6 +59,8 @@
|
||||
"prettier": "^1.18.2",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-native-testing-library": "^1.9.1",
|
||||
"react-test-renderer": "^16.8.6",
|
||||
"release-it": "^12.3.0",
|
||||
"typescript": "^3.5.1"
|
||||
},
|
||||
@@ -73,6 +76,9 @@
|
||||
"<rootDir>/types/",
|
||||
"<rootDir>/lib/"
|
||||
],
|
||||
"testRegex": "/__tests__/.*\\.(test|spec)\\.(js|tsx?)$"
|
||||
"testRegex": "/__tests__/.*\\.(test|spec)\\.(js|tsx?)$",
|
||||
"transform": {
|
||||
"^.+\\.(js|ts|tsx)$": "babel-jest"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import EnsureSingleNavigator from './EnsureSingleNavigator';
|
||||
|
||||
type Props = {
|
||||
initialState?: InitialState;
|
||||
onStateChange?: (state: NavigationState | InitialState) => void;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
@@ -23,7 +24,11 @@ export const NavigationStateContext = React.createContext<{
|
||||
},
|
||||
});
|
||||
|
||||
export default function NavigationContainer({ initialState, children }: Props) {
|
||||
export default function NavigationContainer({
|
||||
initialState,
|
||||
onStateChange,
|
||||
children,
|
||||
}: Props) {
|
||||
const [state, setState] = React.useState<
|
||||
NavigationState | InitialState | undefined
|
||||
>(initialState);
|
||||
@@ -32,7 +37,11 @@ export default function NavigationContainer({ initialState, children }: Props) {
|
||||
|
||||
React.useEffect(() => {
|
||||
stateRef.current = state;
|
||||
});
|
||||
|
||||
if (onStateChange && state !== undefined) {
|
||||
onStateChange(state);
|
||||
}
|
||||
}, [onStateChange, state]);
|
||||
|
||||
const getState = React.useCallback(() => stateRef.current, []);
|
||||
const value = React.useMemo(() => ({ state, getState, setState }), [
|
||||
|
||||
27
src/__tests__/__snapshots__/index.test.tsx.snap
Normal file
27
src/__tests__/__snapshots__/index.test.tsx.snap
Normal file
@@ -0,0 +1,27 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`initializes state with router 1`] = `
|
||||
Object {
|
||||
"index": 1,
|
||||
"key": "root",
|
||||
"names": Array [
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
],
|
||||
"routes": Array [
|
||||
Object {
|
||||
"key": "foo",
|
||||
"name": "foo",
|
||||
},
|
||||
Object {
|
||||
"key": "bar",
|
||||
"name": "bar",
|
||||
},
|
||||
Object {
|
||||
"key": "baz",
|
||||
"name": "baz",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
@@ -1 +0,0 @@
|
||||
it.todo('placeholder');
|
||||
87
src/__tests__/index.test.tsx
Normal file
87
src/__tests__/index.test.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
import * as React from 'react';
|
||||
import { render } from 'react-native-testing-library';
|
||||
import NavigationContainer from '../NavigationContainer';
|
||||
import useNavigationBuilder from '../useNavigationBuilder';
|
||||
import { Router } from '../types';
|
||||
import Screen from '../Screen';
|
||||
|
||||
const MockRouter: Router = {
|
||||
getInitialState({ screens, initialRouteName }) {
|
||||
const routeNames = Object.keys(screens);
|
||||
|
||||
return {
|
||||
key: 'root',
|
||||
names: routeNames,
|
||||
index: routeNames.indexOf(initialRouteName || routeNames[0]),
|
||||
routes: routeNames.map(name => ({
|
||||
key: name,
|
||||
name,
|
||||
})),
|
||||
};
|
||||
},
|
||||
|
||||
getStateForAction() {
|
||||
return null;
|
||||
},
|
||||
|
||||
getStateForChildUpdate(state) {
|
||||
return state;
|
||||
},
|
||||
|
||||
shouldActionPropagateToChildren() {
|
||||
return false;
|
||||
},
|
||||
|
||||
shouldActionChangeFocus() {
|
||||
return false;
|
||||
},
|
||||
|
||||
actionCreators: {},
|
||||
};
|
||||
|
||||
it('initializes state with router', () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const TestNavigator = (props: any) => {
|
||||
useNavigationBuilder(MockRouter, props);
|
||||
return null;
|
||||
};
|
||||
|
||||
const element = (
|
||||
<NavigationContainer
|
||||
onStateChange={state => expect(state).toMatchSnapshot()}
|
||||
>
|
||||
<TestNavigator initialRouteName="bar">
|
||||
<Screen name="foo" component={jest.fn()} />
|
||||
<Screen name="bar" component={jest.fn()} />
|
||||
<Screen name="baz" component={jest.fn()} />
|
||||
</TestNavigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
|
||||
render(element).update(element);
|
||||
});
|
||||
|
||||
it('throws if muliple navigators rendered under one container', async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const TestNavigator = (props: any) => {
|
||||
useNavigationBuilder(MockRouter, props);
|
||||
return null;
|
||||
};
|
||||
|
||||
const element = (
|
||||
<NavigationContainer>
|
||||
<TestNavigator>
|
||||
<Screen name="foo" component={jest.fn()} />
|
||||
</TestNavigator>
|
||||
<TestNavigator>
|
||||
<Screen name="foo" component={jest.fn()} />
|
||||
</TestNavigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
|
||||
expect(() => render(element).update(element)).toThrowError(
|
||||
'Another navigator is already registered for this container'
|
||||
);
|
||||
});
|
||||
@@ -165,7 +165,7 @@ export default function useNavigationBuilder(
|
||||
const state = getState();
|
||||
const result = router.getStateForChildUpdate(state, {
|
||||
update,
|
||||
focus: true,
|
||||
focus,
|
||||
});
|
||||
|
||||
if (handleChildUpdateParent !== undefined) {
|
||||
|
||||
57
yarn.lock
57
yarn.lock
@@ -570,7 +570,30 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
|
||||
"@babel/plugin-transform-react-jsx@^7.0.0 <7.4.0":
|
||||
"@babel/plugin-transform-react-display-name@^7.0.0":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.2.0.tgz#ebfaed87834ce8dc4279609a4f0c324c156e3eb0"
|
||||
integrity sha512-Htf/tPa5haZvRMiNSQSFifK12gtr/8vwfr+A9y69uF0QcU77AVu4K7MiHEkTxF7lQoHOL0F9ErqgfNEAKgXj7A==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-self@^7.0.0":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.2.0.tgz#461e21ad9478f1031dd5e276108d027f1b5240ba"
|
||||
integrity sha512-v6S5L/myicZEy+jr6ielB0OR8h+EH/1QFx/YJ7c7Ua+7lqsjj/vW6fD5FR9hB/6y7mGbfT4vAURn3xqBxsUcdg==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-syntax-jsx" "^7.2.0"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-source@^7.0.0":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.2.0.tgz#20c8c60f0140f5dd3cd63418d452801cf3f7180f"
|
||||
integrity sha512-A32OkKTp4i5U6aE88GwwcuV4HAprUgHcTq0sSafLxjr6AW0QahrCRCjxogkbbcdtpbXkuTOlgpjophCxb6sh5g==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-syntax-jsx" "^7.2.0"
|
||||
|
||||
"@babel/plugin-transform-react-jsx@^7.0.0", "@babel/plugin-transform-react-jsx@^7.0.0 <7.4.0":
|
||||
version "7.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz#f2cab99026631c767e2745a5368b331cfe8f5290"
|
||||
integrity sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg==
|
||||
@@ -750,6 +773,17 @@
|
||||
js-levenshtein "^1.1.3"
|
||||
semver "^5.5.0"
|
||||
|
||||
"@babel/preset-react@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.0.0.tgz#e86b4b3d99433c7b3e9e91747e2653958bc6b3c0"
|
||||
integrity sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-transform-react-display-name" "^7.0.0"
|
||||
"@babel/plugin-transform-react-jsx" "^7.0.0"
|
||||
"@babel/plugin-transform-react-jsx-self" "^7.0.0"
|
||||
"@babel/plugin-transform-react-jsx-source" "^7.0.0"
|
||||
|
||||
"@babel/preset-typescript@^7.3.3":
|
||||
version "7.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.3.3.tgz#88669911053fa16b2b276ea2ede2ca603b3f307a"
|
||||
@@ -7655,7 +7689,7 @@ prettier@^1.18.2:
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea"
|
||||
integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==
|
||||
|
||||
pretty-format@^24.8.0:
|
||||
pretty-format@^24.0.0, pretty-format@^24.8.0:
|
||||
version "24.8.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.8.0.tgz#8dae7044f58db7cb8be245383b565a963e3c27f2"
|
||||
integrity sha512-P952T7dkrDEplsR+TuY7q3VXDae5Sr7zmQb12JU/NDQa/3CH7/QW0yvqLcGN6jL+zQFKaoJcPc+yJxMTGmosqw==
|
||||
@@ -7831,11 +7865,28 @@ react-dom@^16.8.6:
|
||||
prop-types "^15.6.2"
|
||||
scheduler "^0.13.6"
|
||||
|
||||
react-is@^16.8.1, react-is@^16.8.4:
|
||||
react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6:
|
||||
version "16.8.6"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
|
||||
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
|
||||
|
||||
react-native-testing-library@^1.9.1:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-testing-library/-/react-native-testing-library-1.9.1.tgz#458f32ffa86b4f767f05d90475edd04c119f4595"
|
||||
integrity sha512-8yOKu47096p/nl6riIXToidWzmvvoYxVFOG84vb7huT4/HBpfq8FqQJlg7Ck+7Uyq//xBK9c26uAKRsNgTQZWQ==
|
||||
dependencies:
|
||||
pretty-format "^24.0.0"
|
||||
|
||||
react-test-renderer@^16.8.6:
|
||||
version "16.8.6"
|
||||
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.8.6.tgz#188d8029b8c39c786f998aa3efd3ffe7642d5ba1"
|
||||
integrity sha512-H2srzU5IWYT6cZXof6AhUcx/wEyJddQ8l7cLM/F7gDXYyPr4oq+vCIxJYXVGhId1J706sqziAjuOEjyNkfgoEw==
|
||||
dependencies:
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.2"
|
||||
react-is "^16.8.6"
|
||||
scheduler "^0.13.6"
|
||||
|
||||
react@^16.8.6:
|
||||
version "16.8.6"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"
|
||||
|
||||
Reference in New Issue
Block a user