'Onboarding' cannot be used as a JSX component
Hello,
Thank you so much for this amazing library!
After updating to the latest Expo version, I am encountering the following error:
screens/OnboardingScreen.tsx:34:8 - error TS2786: 'Onboarding' cannot be used as a JSX component.
Its type 'typeof Onboarding' is not a valid JSX element type.
Types of construct signatures are incompatible.
Type 'new (props: Props) => Onboarding' is not assignable to type 'new (props: any, deprecatedLegacyContext?: any) => Component<any, any, any>'.
Property 'refs' is missing in type 'Onboarding' but required in type 'Component<any, any, any>'.
34 <Onboarding
~~~~~~~~~~
node_modules/@types/react/index.d.ts:1040:9
1040 refs: {
~~~~
'refs' is declared here.
Found 1 error in screens/OnboardingScreen.tsx:34
I’ve investigated and found that if I update @types/react to the latest version, the error seems to go away. However, the problem is that the latest supported version of @types/react for Expo is 18.3.12, and when running it, expo-doctor fails when using the latest version of React types.
I’m hoping for a solution that resolves this issue without having to upgrade @types/react cause it would mean expo-doctor will fail on my project. Any help would be greatly appreciated!
Thank you in advance.
I am also facing the same issue. Any solutions found yet?? I currently cannot view my onboarding screens.
I have found a temporary fix. Typecasting the onboarding screen types and then prioritizing your types over the intalled package types. Create a root folder of your project called types and add a file named: react-native-onboarding-swiper.d.ts with the following as content:
// types/react-native-onboarding-swiper.d.ts
declare module "react-native-onboarding-swiper" { import * as React from "react";
export interface OnboardingProps { controlStatusBar?: boolean; pages: Array<{ backgroundColor?: string; image?: React.ReactNode; title?: React.ReactNode | string; subtitle?: React.ReactNode | string; titleStyles?: any; subTitleStyles?: any; }>; bottomBarColor?: string; bottomBarHeight?: number; onSkip?: () => void; containerStyles?: any; onDone?: () => void; pageIndexCallback?: (index: number) => void; showSkip?: boolean; }
// Instead of declaring a class, declare Onboarding as a component type. const Onboarding: React.ComponentType<OnboardingProps>; export default Onboarding; }
Remember to priorize your types in the tsconfig.json file in the typeRoots field: { "extends": "expo/tsconfig.base", "compilerOptions": { "jsx": "react-native", "strict": true, "typeRoots": ["./types", "./node_modules/@types"] } }
Restart you vs code and server and everything should work without the typescript errors
Thanks @cassimHamisi, your solution partly solved my implementation but it was missing some props. Here is the final types/react-native-onboarding-swiper.d.ts file:
declare module "react-native-onboarding-swiper" {
import { Component, FC, JSX } from "react";
import {
FlatList,
FlatListProps,
StyleProp,
TextStyle,
ViewStyle,
} from "react-native";
export interface SkipButtonProps {
skipLabel: string | JSX.Element;
isLight: boolean;
allowFontScaling: boolean;
onPress: () => any;
}
export interface NextButtonProps {
nextLabel: string | JSX.Element;
isLight: boolean;
allowFontScaling: boolean;
onPress: () => any;
}
export interface DoneButtonProps {
isLight: boolean;
allowFontScaling: boolean;
onPress: () => any;
}
export interface DotProps {
selected: boolean;
isLight: boolean;
}
export interface Page {
/**
* A background color. The color of the font and dots adapts to the background color.
*/
backgroundColor: string;
/**
* A component (e.g. <Image />) to display at the top of the page.
*/
image: JSX.Element;
/**
* A string OR a React-Native component.
*/
title: string | JSX.Element;
/**
* A string OR a React-Native component.
*/
subtitle: string | JSX.Element;
// INDIVIDUAL PAGE STYLES
/**
* Modify styles of a specific page's title.
*/
titleStyles?: StyleProp<TextStyle> | undefined;
/**
* Modify styles of a specific page's subtitle.
*/
subTitleStyles?: StyleProp<TextStyle> | undefined;
}
export interface Props {
/**
* An array of pages in the following shape.
*/
pages: Page[];
// BUTTONS
/**
* A string OR a React-Native component for the Next label.
* @default "Next"
*/
nextLabel?: string | JSX.Element | undefined;
/**
* A bool flag indicating whether the Next button is visible.
* @default true
*/
showNext?: boolean | undefined;
/**
* A string OR a React-Native component for the Skip label.
* @default "Skip"
*/
skipLabel?: string | JSX.Element | undefined;
/**
* A bool flag indicating whether the Skip button is visible.
* @default true
*/
showSkip?: boolean | undefined;
/**
* A callback that is fired if the Onboarding is skipped.
*/
onSkip?: (() => any) | undefined;
/**
* When pressing skip, go to that page (e.g. skipToPage={2}). If this prop is provided, ignores onSkip.
*/
skipToPage?: number | undefined;
/**
* A callback that is fired after the Onboarding is completed.
*/
onDone?: (() => any) | undefined;
/**
* A bool flag indicating whether the Done checkmark button is visible.
* @default true
*/
showDone?: boolean | undefined;
// GENERAL
/**
* A number for the height of the bottom bar.
* @default 60
*/
bottomBarHeight?: number | undefined;
/**
* BackgroundColor of the bottom bar.
* @default "transparent"
*/
bottomBarColor?: string | undefined;
/**
* A bool flag indicating whether the bottom bar should be highlighted.
* @default true
*/
bottomBarHighlight?: boolean | undefined;
/**
* A bool flag indicating whether the status bar should change with the background color.
* @default true
*/
controlStatusBar?: boolean | undefined;
/**
* Whether to show the bottom pagination bar.
* @default true
*/
showPagination?: boolean | undefined;
/**
* Additional props for the FlatList which holds all the pages.
*/
flatlistProps?: FlatListProps<Page> | undefined;
/**
* The duration in milliseconds for the animation of the background color for the page transition.
* @default 500
*/
transitionAnimationDuration?: number | undefined;
/**
* Font scaling can cause troubles with high-resolution screens. You may want to disable it.
* @default true
*/
allowFontScaling?: boolean | undefined;
/**
* A function that receives the page index as a parameter on page change. Example Usage.
*/
pageIndexCallback?: ((pageIndex: number) => any) | undefined;
// DEFAULT PAGE STYLES
/**
* Override the default container styles.
*/
containerStyles?: StyleProp<ViewStyle> | undefined;
/**
* Override the default image container styles e.g. the paddingBottom of 60.
*/
imageContainerStyles?: StyleProp<ViewStyle> | undefined;
/**
* Override the default title styles.
*/
titleStyles?: StyleProp<TextStyle> | undefined;
/**
* Override the default subtitle styles.
*/
subTitleStyles?: StyleProp<TextStyle> | undefined;
// CUSTOM COMPONENTS
/**
* Skip Button, gets skipLabel as prop.
*/
SkipButtonComponent?: FC<SkipButtonProps> | undefined;
/**
* Next Button, gets nextLabel as prop.
*/
NextButtonComponent?: FC<NextButtonProps> | undefined;
/**
* Done Button.
*/
DoneButtonComponent?: FC<DoneButtonProps> | undefined;
/**
* Dot for the pagination, gets selected as prop to indicate the active page.
*/
DotComponent?: FC<DotProps> | undefined;
}
export default class Onboarding extends Component<Props> {
flatList?: FlatList;
goNext: () => void;
}
}
And as you said, do not forget to add the types folder path to your tsconfig.json:
"typeRoots": ["./types", "./node_modules/types"]
Thanks @cassimHamisi and @juanmigdr , I ran into the same issue and the solution of creating a custom react-native-onboarding-swiper.d.ts file worked for me as well.
I placed the file in the root of the project and added it to tsconfig.json under include like this:
"include": [
"**/*.ts",
"**/*.tsx",
".expo/types/**/*.ts",
"expo-env.d.ts",
"./react-native-onboarding-swiper.d.ts"
]
After that, the error went away.
Hopefully this issue will be fixed soon so we can remove the custom .d.ts file.
One more tip: for better typing you can also import the Page type directly from the library:
import Onboarding, { type Page } from 'react-native-onboarding-swiper';