5

I am adapting a ReactNative mobile app to ReactNative Web. The app is done with react-navigation.

Currently, every time I set the params of a route (either through navigate or setParams), those params show in the URL. I end up with bad looking URLs like so: http://localhost:19006/me/undefined?user=%5Bobject%20Object%5D

Either that or the URL contains irrelevant data for the user and generally looks messy.

Is there a way to not show the route params inside the URL?

Ryan Pergent
  • 4,432
  • 3
  • 36
  • 78

4 Answers4

5

You should re-consider if params is an appropriate place to have this data if you don't want in the URL. That you think that the URL contains irrelevant data is a sign that the data doesn't belong in the navigation state.

If you visit a screen directly from a URL, it should render the same as when you navigated to it porgrammatically. If you're passing something in params, it means that that information is needed for the screen to render correctly, and if you remove it from the URL, then that information is lost. Consider that it's possible to open the page directly from a URL, either on Web or with a deep link. If the required data isn't available, then it's not going to work.

In your case, seems like you're passing a full user object (maybe not, hard to say without code). Ideally, this object should be in your global store instead of params, and you should only pass the user id in params. Then you should gran the full object from your global store using that id, or trigger a data fetch if the objet isn't fetched yet (if needed).

You didn't specify the version of React Navigation in your question. In v5, you can customize how your params are stringified to URLs, and how they are parsed back using the stringify and parse options:

const linking = {
  screens: {
    Profile: {
      path: 'user/:id',
      parse: {
        id: (id) => id.replace(/^@/, '')
      },
      stringify: {
        id: (id) => `@{id}`,
      },
    },
  },
};

This should help you with making URLs look prettier, and handle cases where params are not simple strings. However you can't omit params from the URL altogether since they are necessary data for the screen to render.

More details: https://reactnavigation.org/docs/configuring-links#passing-params

satya164
  • 9,464
  • 2
  • 31
  • 42
  • 1
    I see what you mean and I will try to change it in most cases, thanks. However, I sometimes need to send data back data to a previous screen with `navigate`. This is what I would still call irrelevant data. It only pertains to the current session and shouldn't be sent again in case of a page refresh. – Ryan Pergent Oct 28 '20 at 11:49
  • @RyanPergent even for cases such as this, that data isn't irrelevant. imagine that the user refreshed the page, or Ctrl+Click/Cmd+Clicked the button to open in a new tab instead. The data being in the URL means it's going to work as expected in both cases. – satya164 Oct 28 '20 at 11:54
  • Let's say that I have a stack called `ProfileStack`, which has userId as a param. I want every screen in this stack to have access to this userId so I pass it down using `initialParams`. For user `78`, I want my URL to be `profile/78/some-menu` (with `some-menu` changing for each screen). The problem is that it ends up being `profile/78/some-menu?userId=78`... It's quite irrelevant because without "?userId=78" in the URL, I can still display the same page on reload, isn't it? Not sure how else to handle this case. – Ryan Pergent Oct 28 '20 at 14:18
  • Okay, nevermind. I am not sure how it works, but it seems that react-navigation won't add the `initialParams` at the end of the URL if they are are part of the stack `path` config. I cannot find the doc that explains the rule for it. It's definitely good, but I would love to know the limitations. – Ryan Pergent Oct 28 '20 at 14:55
  • It should never do `profile/78/some-menu?userId=78` regardless if they are initial params or not. The query param won't be added if it's part of the path already. (https://reactnavigation.org/docs/configuring-links#passing-params) Can you open an issue about when you see the duplication happening? It sounds like a bug. – satya164 Oct 28 '20 at 15:03
0

satya164's answer is definitely the proper path to follow. Just wanted to also post this solution as it is a direct answer to the question, even if not the most advisable.

import { getPathFromState} from "@react-navigation/native";

const linking = {
  screens: {
    ...
  },
  getPathFromState(state, config){
     let path = getPathFromState(state, config);
     const index = path.indexOf("?")
     if(index>=0){
        path = path.substr(0, index);
     }
     return path;
  }
};
Ryan Pergent
  • 4,432
  • 3
  • 36
  • 78
0

NOTE: To use this solution you need to make sure that every object and function parameters are optional, otherwise if you reload the page you will get an error.

I removed every object and function from the url adding this custom getPathFromState to linkingOptions:

const linking = {
  config: {
    screens: {
      ...
    }
  },
  getPathFromState: (state, options) => {
    const cleanState = {
      ...state,
      routes: state.routes.map(route => {
        if(!route.params) {
          return route
        }

        const cleanParams = {}
        for(const param in route.params) {
          const value = route.params[param]
          if(typeof value !== "object" && typeof value !== "function") {
            cleanParams[param] = value
          }
        }
        return {
          ...route,
          params: cleanParams,
        }
      }),
    }
    return getPathFromState(cleanState, options) //imported from @react-navigation/native
  },
}
Alessio Cancian
  • 161
  • 1
  • 2
  • 6
-1

You can pass the parameters the component needs as a prop

like this

navigation.navigate('Details', {
     itemId: 86,
     otherParam: 'anything you want here',
     });

then in Details Component

const { itemId , otherParam} = route.params;

Alternatively, if you use Redux/Mobx or any other global state management

You can pull the data from there and not pass it through the URL then get data with the help connect or with useSelector hooks

Yoel
  • 7,555
  • 6
  • 27
  • 59
  • My question is maybe not clear enough. I know how to send params and I do it as you described. My problem is that these params are showing in the URL on the page I navigate to. I would like them to not show in the URL. – Ryan Pergent Oct 28 '20 at 10:05