Skip to content

Commit

Permalink
fix: use console.error for linking conflicts instead of throwing
Browse files Browse the repository at this point in the history
  • Loading branch information
satya164 committed Nov 27, 2022
1 parent ecf0cf8 commit 5175b18
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 39 deletions.
39 changes: 19 additions & 20 deletions packages/native/src/__tests__/useLinking.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ it('throws if multiple instances of useLinking are used', () => {
return null;
}

const spy = jest.spyOn(console, 'error').mockImplementation();

let element: RenderAPI | undefined;

expect(() => (element = render(<Sample />))).toThrowError(
element = render(<Sample />);

expect(spy).toHaveBeenCalledTimes(1);
expect(spy.mock.calls[0][0]).toMatch(
'Looks like you have configured linking in multiple places.'
);

Expand All @@ -36,15 +41,17 @@ it('throws if multiple instances of useLinking are used', () => {
return null;
}

expect(
() =>
(element = render(
<>
<A />
<B />
</>
))
).toThrowError('Looks like you have configured linking in multiple places.');
element = render(
<>
<A />
<B />
</>
);

expect(spy).toHaveBeenCalledTimes(2);
expect(spy.mock.calls[1][0]).toMatch(
'Looks like you have configured linking in multiple places.'
);

element?.unmount();

Expand All @@ -57,17 +64,9 @@ it('throws if multiple instances of useLinking are used', () => {

render(wrapper2).unmount();

expect(() => (element = render(wrapper2))).not.toThrow();

element?.unmount();

function Sample3() {
useLinking(ref, options);
useLinking(ref, { ...options, enabled: false });
return null;
}
render(wrapper2);

expect(() => (element = render(<Sample3 />))).not.toThrowError();
expect(spy).toHaveBeenCalledTimes(2);

element?.unmount();
});
30 changes: 21 additions & 9 deletions packages/native/src/useLinking.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type Options = LinkingOptions<ParamListBase> & {
independent?: boolean;
};

let isUsingLinking = false;
let linkingHandlers: Symbol[] = [];

export default function useLinking(
ref: React.RefObject<NavigationContainerRef<ParamListBase>>,
Expand Down Expand Up @@ -56,31 +56,43 @@ export default function useLinking(
}: Options
) {
React.useEffect(() => {
if (process.env.NODE_ENV === 'production') {
return undefined;
}

if (independent) {
return undefined;
}

if (enabled !== false && isUsingLinking) {
throw new Error(
if (enabled !== false && linkingHandlers.length) {
console.error(
[
'Looks like you have configured linking in multiple places. This is likely an error since deep links should only be handled in one place to avoid conflicts. Make sure that:',
"- You are not using both 'linking' prop and 'useLinking'",
"- You don't have 'useLinking' in multiple components",
"- You don't have multiple NavigationContainers in the app each with 'linking' enabled",
'- Only a single instance of the root component is rendered',
Platform.OS === 'android'
? "- You have set 'android:launchMode=singleTask' in the '<activity />' section of the 'AndroidManifest.xml' file to avoid launching multiple instances"
: '',
]
.join('\n')
.trim()
);
} else {
isUsingLinking = enabled !== false;
}

const handler = Symbol();

if (enabled !== false) {
linkingHandlers.push(handler);
}

return () => {
isUsingLinking = false;
const index = linkingHandlers.indexOf(handler);

if (index > -1) {
linkingHandlers.splice(index, 1);
}
};
});
}, [enabled, independent]);

// We store these options in ref to avoid re-creating getInitialState and re-subscribing listeners
// This lets user avoid wrapping the items in `React.useCallback` or `React.useMemo`
Expand Down
32 changes: 22 additions & 10 deletions packages/native/src/useLinking.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ const series = (cb: () => Promise<void>) => {
return callback;
};

let isUsingLinking = false;
let linkingHandlers: Symbol[] = [];

type Options = LinkingOptions<ParamListBase> & {
independent?: boolean;
Expand All @@ -305,28 +305,40 @@ export default function useLinking(
}: Options
) {
React.useEffect(() => {
if (process.env.NODE_ENV === 'production') {
return undefined;
}

if (independent) {
return undefined;
}

if (enabled !== false && isUsingLinking) {
throw new Error(
if (enabled !== false && linkingHandlers.length) {
console.error(
[
'Looks like you have configured linking in multiple places. This is likely an error since URL integration should only be handled in one place to avoid conflicts. Make sure that:',
"- You are not using both 'linking' prop and 'useLinking'",
"- You don't have 'useLinking' in multiple components",
'Looks like you have configured linking in multiple places. This is likely an error since deep links should only be handled in one place to avoid conflicts. Make sure that:',
"- You don't have multiple NavigationContainers in the app each with 'linking' enabled",
'- Only a single instance of the root component is rendered',
]
.join('\n')
.trim()
);
} else {
isUsingLinking = enabled !== false;
}

const handler = Symbol();

if (enabled !== false) {
linkingHandlers.push(handler);
}

return () => {
isUsingLinking = false;
const index = linkingHandlers.indexOf(handler);

if (index > -1) {
linkingHandlers.splice(index, 1);
}
};
});
}, [enabled, independent]);

const [history] = React.useState(createMemoryHistory);

Expand Down

0 comments on commit 5175b18

Please sign in to comment.