fix: add warning when passing inline function to component prop

This commit is contained in:
Satyajit Sahoo
2020-01-30 05:01:25 +01:00
parent d0510d0220
commit fa4a959549
5 changed files with 38 additions and 29 deletions

View File

@@ -233,8 +233,8 @@ it('handle dispatching with ref', () => {
<Screen name="foo2">
{() => (
<ChildNavigator>
<Screen name="qux" component={() => null} />
<Screen name="lex" component={() => null} />
<Screen name="qux">{() => null}</Screen>
<Screen name="lex">{() => null}</Screen>
</ChildNavigator>
)}
</Screen>
@@ -242,8 +242,8 @@ it('handle dispatching with ref', () => {
<Screen name="baz">
{() => (
<ChildNavigator>
<Screen name="qux" component={() => null} />
<Screen name="lex" component={() => null} />
<Screen name="qux">{() => null}</Screen>
<Screen name="lex">{() => null}</Screen>
</ChildNavigator>
)}
</Screen>
@@ -307,8 +307,8 @@ it('handle resetting state with ref', () => {
<Screen name="foo2">
{() => (
<TestNavigator>
<Screen name="qux" component={() => null} />
<Screen name="lex" component={() => null} />
<Screen name="qux">{() => null}</Screen>
<Screen name="lex">{() => null}</Screen>
</TestNavigator>
)}
</Screen>
@@ -316,8 +316,8 @@ it('handle resetting state with ref', () => {
<Screen name="baz">
{() => (
<TestNavigator>
<Screen name="qux" component={() => null} />
<Screen name="lex" component={() => null} />
<Screen name="qux">{() => null}</Screen>
<Screen name="lex">{() => null}</Screen>
</TestNavigator>
)}
</Screen>
@@ -394,12 +394,12 @@ it('handles getRootState', () => {
<Screen name="foo">
{() => (
<TestNavigator>
<Screen name="qux" component={() => null} />
<Screen name="lex" component={() => null} />
<Screen name="qux">{() => null}</Screen>
<Screen name="lex">{() => null}</Screen>
</TestNavigator>
)}
</Screen>
<Screen name="bar" component={() => null} />
<Screen name="bar">{() => null}</Screen>
</TestNavigator>
</NavigationContainer>
);

View File

@@ -952,7 +952,7 @@ it('throws if no name is passed to Screen', () => {
);
expect(() => render(element).update(element)).toThrowError(
'We got an invalid name (undefined) for the screen. It must be a non-empty string.'
'Got an invalid name (undefined) for the screen. It must be a non-empty string.'
);
});
@@ -971,7 +971,7 @@ it('throws if invalid name is passed to Screen', () => {
);
expect(() => render(element).update(element)).toThrowError(
'We got an invalid name ([]) for the screen. It must be a non-empty string.'
'Got an invalid name ([]) for the screen. It must be a non-empty string.'
);
});
@@ -992,7 +992,7 @@ it('throws if both children and component are passed', () => {
);
expect(() => render(element).update(element)).toThrowError(
"We got both 'component' and 'children' props for the screen 'foo'. You must pass only one of them."
"Got both 'component' and 'children' props for the screen 'foo'. You must pass only one of them."
);
});
@@ -1011,7 +1011,7 @@ it('throws descriptive error for undefined screen component', () => {
);
expect(() => render(element).update(element)).toThrowError(
"We couldn't find a 'component' or 'children' prop for the screen 'foo'"
"Couldn't find a 'component' or 'children' prop for the screen 'foo'"
);
});
@@ -1030,7 +1030,7 @@ it('throws descriptive error for invalid screen component', () => {
);
expect(() => render(element).update(element)).toThrowError(
"We got an invalid value for 'component' prop for the screen 'foo'. It must be a a valid React Component."
"Got an invalid value for 'component' prop for the screen 'foo'. It must be a a valid React Component."
);
});
@@ -1049,7 +1049,7 @@ it('throws descriptive error for invalid children', () => {
);
expect(() => render(element).update(element)).toThrowError(
"We got an invalid value for 'children' prop for the screen 'foo'. It must be a function returning a React Element."
"Got an invalid value for 'children' prop for the screen 'foo'. It must be a function returning a React Element."
);
});

View File

@@ -592,7 +592,7 @@ it('returns true for canGoBack when parent router handles GO_BACK', () => {
<Screen name="qux">
{() => (
<OverrodeNavigator>
<Screen name="qux" component={() => null} />
<Screen name="qux">{() => null}</Screen>
</OverrodeNavigator>
)}
</Screen>

View File

@@ -181,8 +181,8 @@ it("lets children handle the action if parent didn't", () => {
<Screen name="baz">
{() => (
<ChildNavigator>
<Screen name="qux" component={() => null} />
<Screen name="lex" component={() => null} />
<Screen name="qux">{() => null}</Screen>
<Screen name="lex">{() => null}</Screen>
</ChildNavigator>
)}
</Screen>
@@ -291,8 +291,8 @@ it("action doesn't bubble if target is specified", () => {
<Screen name="baz">
{() => (
<ChildNavigator>
<Screen name="qux" component={() => null} />
<Screen name="lex" component={() => null} />
<Screen name="qux">{() => null}</Screen>
<Screen name="lex">{() => null}</Screen>
</ChildNavigator>
)}
</Screen>
@@ -356,8 +356,8 @@ it('logs error if no navigator handled the action', () => {
<Screen name="baz">
{() => (
<TestNavigator>
<Screen name="qux" component={() => null} />
<Screen name="lex" component={() => null} />
<Screen name="qux">{() => null}</Screen>
<Screen name="lex">{() => null}</Screen>
</TestNavigator>
)}
</Screen>

View File

@@ -92,7 +92,7 @@ const getRouteConfigsFromChildren = <ScreenOptions extends object>(
if (typeof name !== 'string' || !name) {
throw new Error(
`We got an invalid name (${JSON.stringify(
`Got an invalid name (${JSON.stringify(
name
)}) for the screen. It must be a non-empty string.`
);
@@ -101,24 +101,33 @@ const getRouteConfigsFromChildren = <ScreenOptions extends object>(
if (children != null || component !== undefined) {
if (children != null && component !== undefined) {
throw new Error(
`We got both 'component' and 'children' props for the screen '${name}'. You must pass only one of them.`
`Got both 'component' and 'children' props for the screen '${name}'. You must pass only one of them.`
);
}
if (children != null && typeof children !== 'function') {
throw new Error(
`We got an invalid value for 'children' prop for the screen '${name}'. It must be a function returning a React Element.`
`Got an invalid value for 'children' prop for the screen '${name}'. It must be a function returning a React Element.`
);
}
if (component !== undefined && !isValidElementType(component)) {
throw new Error(
`We got an invalid value for 'component' prop for the screen '${name}'. It must be a a valid React Component.`
`Got an invalid value for 'component' prop for the screen '${name}'. It must be a a valid React Component.`
);
}
if (typeof component === 'function' && component.name === 'component') {
// Inline anonymous functions passed in the `component` prop will have the name of the prop
// It's relatively safe to assume that it's not a component since it should also have PascalCase name
// We won't catch all scenarios here, but this should catch a good chunk of incorrect use.
console.warn(
`Looks like you're passing an inline function for 'component' prop for the screen '${name}' (e.g. component={() => <SomeComponent />}). Passing an inline function will cause the component state to be lost on re-render and cause perf issues since it's re-created every render. You can pass the function as children to 'Screen' instead to achieve the desired behaviour.`
);
}
} else {
throw new Error(
`We couldn't find a 'component' or 'children' prop for the screen '${name}'. This can happen if you passed 'undefined'. You likely forgot to export your component from the file it's defined in, or mixed up default import and named import when importing.`
`Couldn't find a 'component' or 'children' prop for the screen '${name}'. This can happen if you passed 'undefined'. You likely forgot to export your component from the file it's defined in, or mixed up default import and named import when importing.`
);
}
});