I have a simple React Native app I'm putting together using Typescript and I'm trying to understand how to make the navigation work correctly.
I a list of content sections and when one is selected to open the chosen article in a webview. What I can't grasp is how I am supposed to pass the URL for the webview to load to the view that contains it. Both the navigation list and the web view should fill the screen when they are selected.
As things stand my base component is GuidanceNavigation
which contains a Stack.Navigator
with a Stack.Screen
for the NavigationItems
view that lists all the topics and a Stack.Screen
for the InstructionView
that contains the webview to show the instructions.
As things stand these are all React.Component
types and the part I am not clear on is that when I am in the NavigationItems
view I select an option and I need the parent view to replace the NavigationItems
view with InstructionView
, providing the InstructionView
with the title and file location for the selected article. As far as I can tell React Navigation does some magic involving passing in some navigation properties, but I can't figure out how that is supposed to work in a Typescript context or how I can pass my typed objects through the Stack Navigator or even whether the Stack Navigator is the correct component to use in this situation. The Typescript-specific documentation talks about passing through navigation properties but doesn't explain how this is related to the navigator
object that seems to be available in JavaScript to actually perform navigation.
My code looks like this, it's a while since I have worked with React and my first time using react-native so it's probably neither excellent nor idiomatic:
GuidanceNavigation.tsx:
const Stack = createStackNavigator();export class GuidanceNavigation extends React.Component<{}, {}> { render(): JSX.Element { return (<SafeAreaView style={styles.container} ><NavigationContainer><Stack.Navigator><Stack.Screen name="Choose a topic" component="NavigationItems" /><Stack.Screen name="Instructions" component="InstructionView" /></Stack.Navigator></NavigationContainer></SafeAreaView> ); };}
NavigationTypes.ts:
export interface IFileLink { title: string, file: string}
NavigationItems.tsx:
import { IFileLink } from './NavigationTypes';export class NavigationItems extends React.Component<{}, {}> { itemId: number = 0; readonly items = [ { section: R.strings.menu_steps, values: [ { title: R.strings.menu_getting_started, file: "./assets/html/getting-started.html" }, // and so on ] }, { section: R.strings.menu_guidance, values: [ { title: R.strings.menu_glossary, file: "./assets/html/glossary.html" }, // etc ] } ]; itemList(itemList: Array<IFileLink>): JSX.Element[] { return itemList.map((it) => this.item(it)); }; navigateToFile(link:IFileLink) { console.log("Navigation to "+link.title); // This does not work because navigation comes from ??? somewhere??? navigation.navigate('Instructions', link); }; item(fileLink:IFileLink): JSX.Element { return(<Button key= { this.itemId++ } title= { fileLink.title } onPress= {() => this.navigateToFile(fileLink) } /> ); }; render(): JSX.Element { return (<ScrollView><Text style={styles.sectionTitle}>{this.items[0].section}</Text> {this.itemList(this.items[0].values)}<Text style={styles.sectionTitle}>{this.items[1].section}</Text> {this.itemList(this.items[1].values)}</ScrollView> ) };}
InstructionView.tsx:
import { IFileLink } from './NavigationTypes';export class InstructionView extends React.Component<IFileLink> { private fileLink: IFileLink; constructor(fl: IFileLink) { super(fl); this.fileLink = fl; } render(): JSX.Element { return (<WebView source={{ uri: this.fileLink.file }} /> ); }}
How can I ensure that I navigate from NavigationItems
to InstructionView
with the required properties when an item is selected in that list?