I’ve a Sections screen that gets quiz data from database and passes it off to Quiz screen based on the Section.
The structure of the data from database is:
{
sections: [
{
questions: [
{
question: "",
options: ["", "", ""],
answer: "",
...
}
Since I’m using React Navigation with TypeScript I need to define the RootStackParamList
for Section and Quiz screen, something like:
type RootStackParamList = {
Home: undefined;
Modules: undefined;
Sections: {data: {}};
Quiz: {data: {}};
};
Navigating across screens like:
{data.sections.slice(1).map((section, index) => (
<TouchableOpacity
key={index}
onPress={() => navigation.navigate('Quiz', {data: section.questions})}
</TouchableOpacity>
))}
I get the following error message on the line when navigating to the new screen with params onPress={() => navigation.navigate('Quiz', {data: section.questions})}
:
Argument of type '{ data: any; }' is not assignable to parameter of type '{ sections: [{ questions: []; }]; }'.
Object literal may only specify known properties, and 'data' does not exist in type '{ sections: [{ questions: []; }]; }'.ts(2345)
How can I define RootStackParamList
in order to fix the error?
ModuleList.tsx
import * as React from 'react';
import {
ScrollView,
Text,
TouchableOpacity,
StyleSheet,
useColorScheme,
SafeAreaView,
} from 'react-native';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {useState, useEffect} from 'react';
import {List} from 'react-native-paper';
import {db} from '../../firebase';
import {ref, onValue} from 'firebase/database';
// import { AdmobContext } from "../components/AdmobController";
import {StackNavigationProp} from '@react-navigation/stack';
type RootStackParamList = {
Home: undefined;
Modules: undefined;
Sections: {data: {}};
Quiz: undefined;
};
type ModuleListScreenNavigationProp = StackNavigationProp<
RootStackParamList,
'Modules'
>;
type Props = {
navigation: ModuleListScreenNavigationProp;
};
const ModuleList = ({navigation}: Props) => {
const [quiz, setQuiz] = useState({});
const isDarkMode = useColorScheme() === 'dark';
const style = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
color: isDarkMode ? Colors.lighter : Colors.darker,
optionBackgroundColor: isDarkMode ? '#333333' : '#D3D3D3',
};
// let { renderBanner } = useContext(AdmobContext);
useEffect(() => {
return onValue(ref(db, '/'), (querySnapShot: {val: () => {}}) => {
const data = querySnapShot.val() || {};
let quizItems = {...data};
setQuiz(quizItems);
});
}, []);
return (
<ScrollView
style={[styles.container, {backgroundColor: style.backgroundColor}]}>
<SafeAreaView>
<TouchableOpacity
onPress={() => navigation.navigate('Sections', {data: quiz})}
style={[
styles.listItem,
{backgroundColor: style.optionBackgroundColor},
]}>
<Text style={[styles.text, {color: style.color}]}>
Security Guard Training
</Text>
<List.Icon color={style.color} icon="security" />
</TouchableOpacity>
<TouchableOpacity
onPress={() => navigation.navigate('Sections', {data: quiz})}
style={[
styles.listItem,
{backgroundColor: style.optionBackgroundColor},
]}>
<Text style={[styles.text, {color: style.color}]}>Useful Links</Text>
<List.Icon color={style.color} icon="link" />
</TouchableOpacity>
</SafeAreaView>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingVertical: 30,
paddingHorizontal: 20,
position: 'relative',
},
listItem: {
borderRadius: 10,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 1,
paddingHorizontal: 10,
paddingVertical: 15,
},
text: {
fontSize: 18,
marginHorizontal: 15,
},
});
export default ModuleList;
SectionList.tsx
import * as React from 'react';
import {
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
useColorScheme,
} from 'react-native';
import {List} from 'react-native-paper';
// import { AdmobContext } from "../components/AdmobController";
import {StackNavigationProp} from '@react-navigation/stack';
import {RouteProp} from '@react-navigation/native';
import {Colors} from 'react-native/Libraries/NewAppScreen';
type QuestionDataType = {
question: string;
options: string[];
answer: string;
};
type SectionDataType = {
sections: {
questions: QuestionDataType[];
}[];
};
type RootStackParamList = {
Home: undefined;
Modules: undefined;
Sections: {data: QuestionDataType[]};
Quiz: {data: QuestionDataType[]};
};
type SectionListScreenNavigationProp = StackNavigationProp<
RootStackParamList,
'Sections'
>;
type SectionListScreenRouteProp = RouteProp<RootStackParamList, 'Sections'>;
type Props = {
navigation: SectionListScreenNavigationProp;
route: SectionListScreenRouteProp;
};
const SectionList = ({navigation, route}: Props) => {
const data = route.params.data;
const isDarkMode = useColorScheme() === 'dark';
const style = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
color: isDarkMode ? Colors.lighter : Colors.darker,
optionBackgroundColor: isDarkMode ? '#333333' : '#D3D3D3',
};
// let { renderBanner } = useContext(AdmobContext);
return (
<ScrollView
style={[styles.container, {backgroundColor: style.backgroundColor}]}>
<TouchableOpacity
key={1}
onPress={() =>
navigation.navigate('Quiz', {data: data.sections[0].questions})
}
style={[
styles.listItem,
{backgroundColor: style.optionBackgroundColor},
]}>
<Text style={[styles.text, {color: style.color}]}>Section 1</Text>
<List.Icon color={style.color} icon="frequently-asked-questions" />
</TouchableOpacity>
{data.sections.slice(1).map((section, index) => (
<TouchableOpacity
key={index}
onPress={() => navigation.navigate('Quiz', {data: section.questions})}
style={[
styles.listItem,
{backgroundColor: style.optionBackgroundColor},
]}>
<Text style={[styles.text, {color: style.color}]}>
{'Section '}
{index + 2}
</Text>
<List.Icon color={style.color} icon="frequently-asked-questions" />
</TouchableOpacity>
))}
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingVertical: 30,
paddingHorizontal: 20,
position: 'relative',
},
listItem: {
borderRadius: 10,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 1,
paddingHorizontal: 10,
paddingVertical: 15,
},
text: {
fontSize: 18,
marginHorizontal: 15,
},
});
export default SectionList;
2
Answers
You can first define types for your section and question like this:
Then inside the RootStackParamList type:
And please remember when you get data from the server (your database), for the variable/state that store the response define SectionDataType till everything be ok when use that for passing the data in the navigate.
At the end your navigation section will execute without error:
I have a handy-dandy way to declare my React-Navigation thigs.
Inside your
AppNavigator.tsx
And then inside your
Home.tsx
andSettings.tsx
component:Hope it will help to make sure your data will be typed correctly for every screen you will make.
Make sure your data is serializable (you should not pass functions as arguments), if not you will receive some warnings about screen-to-screen communication.