Search code examples
react-nativenavigationreact-navigation

React-Native navigation doesn't recognize params


I have a typescript react-native application. I have used navigation with some sucess but in this case, no matter what I do, the id, filename, and file are all undefined.

Here is the code with the issue. I know according to react-native navigation doing what I'm doing with the file isn't necessary great coding practice, but this is just displaying a file, so it's not a huge deal. (I am storing the filename and id in a sqlite database). I added the useState hoping that the file gets passed or change that it can change the state.


    export type Props = {
      navigation: PropTypes.func.isRequired;
      id:PropTypes.int.isRequired;
      filename:Protypes.string.isRequired;
      file:{ 
        name: PropTypes.string.isRequired;
        uri: PropTypes.path.isRequired;
        type: PropTypes.mime.isRequired};
    };
    
    const FileViewScreen: React.FC<Props> = ({navigation,id,filename,file}) => {
      console.log("File View Screen?")
      console.log("currentFile");
      console.log(id)
      console.log(currentFile)
      console.log(filename)
      console.log(file)
      const [currentFile,setCurrentFile] = useState(file);

Here is where the user gets routed to the FileScreen. Here I was testing to see if any id is passed, I'm aware that the id needs changed to the id and not 1 but this was testing.

const HomeScreen: React.FC<Props> = ({navigation}) => {
  const [loading, setLoading] = useState(false);
  const [file, setFile] = useState({});
  const [files, setFiles] = useState([]);

  const downloadFile = async () => {
    try {
      ...

      const newEntry = {
        name: 'ImageFileName' + Math.random().toString(),
        uri: result.path,
        type: result.mime,
      };
      const res = await addFile(result.path);
      console.log(res)
      navigation.navigate('FileView', { id:1,filename:res,file:newEntry });
    } catch (error) {
      console.log('downloadFile error', error);
    }
  };

  return (
    <View style={styles}>
      <Text>Welcome Home</Text>
      {loading && <ActivityIndicator size={'large'} color="#000" />}
      {!loading && (
        <>
          <Button
            title="Start Recording"
            onPress={downloadFile}
          />

Here is the addFile function. I don't think this matters but I've been wrong before. Here

export const addFile = file_path => {
  db.transaction(txn => {
    console.log("db transaction")
    console.log(file_path)
    const response = txn.executeSql(
      'INSERT INTO files(file_path,uploaded) VALUES (' +
        file_path +
        ',' +
        false +
        ')',
      (sqlTxn, res) => {
        console.log("adding")
        console.log(`${file_path} video added successfully`);
        return file_path;
      },
      error => {
        console.log('error on adding file ' + error.message);
        return 0;
      },
    );
  });
  console.log(resopnse)
};

In my app.js (i do have a working register and, login, home screen. Right now this is the only time I have an issue.

  <NavigationContainer>
      <Stack.Navigator initialRouteName={initalRoute}>
        <Stack.Screen name="Login">
          {props => (
            <LoginScreen {...props} setToken={setUserToken} setUser={setUser} />
          )}
        </Stack.Screen>
        <Stack.Screen name="Home">
            {props => (
              <HomeScreen {...props}/>
            )}
        </Stack.Screen>
        <Stack.Screen name="Register" component={RegisterScreen} />
        <Stack.Screen name="FileView">
          {props =>(
             <FileViewScreen {...props} />
             )}
        </Stack.Screen>
</NavigationContainer>

Things that I've tried.

  1. I tried to change the RecordingView in app.js to make sure it's specifically passing props
  2. I've changed props to be only an id, only a filename, or only the newentry.
  3. I've tried to set the state as the file in case it gets passed later.

Things that I haven't tried

  1. I haven't put this in a button. That's the main thing I haven't been able to find if navigation.navigate only works on a push event. I don't see any documentation stating that.

Solution

  • If your FileViewScreen is a child component of some parent view then id,filename,file will be available from component props object. If instead you navigate to FileViewScreen from another screen then id,filename,file will be part of route prop.

    To account for both use cases you could so something like this

    const FileViewScreen: React.FC<Props> = (props) {
      // try extracting props from root prop object
      let { id,filename,file } = props;
    
    
      // if navigation route params are available, 
      // then extract props from route.params instead
      // you could also check if id, filename, file etc are null
      // before extracting from route.params
      const { route }  = props;
      if (route && route.params) {
        ({ id,filename,file } = route.params);
      }
      ...
    }