使用 react-navigation 从 url 隐藏路由参数

Hide route params from the url with react-navigation

我正在将 ReactNative 移动应用程序改编为 ReactNative Web。该应用已完成 react-navigation

目前,每次我设置路由的参数(通过 navigatesetParams)时,这些参数都会显示在 URL 中。我最终看起来很糟糕 URLs 像这样: http://localhost:19006/me/undefined?user=%5Bobject%20Object%5D

那个或 URL 包含与用户无关的数据,通常看起来很乱。

有没有办法不在 URL 中显示路由参数?

您可以将组件需要的参数作为 prop 传递

像这样

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

然后在详细信息组件中

const { itemId , otherParam} = route.params;

或者,如果您使用 Redux/Mobx 或任何其他全局状态管理

您可以从那里提取数据,而不是通过 URL 然后借助 connectuseSelector hooks

获取数据

如果您不想在 URL 中,如果 params 是存放此数据的合适位置,您应该 re-consider。如果您认为 URL 包含不相关的数据,则表明该数据不属于导航状态。

如果您直接从 URL 访问屏幕,它应该呈现与您以编程方式导航到它时相同的呈现方式。如果您在参数中传递某些内容,则意味着屏幕需要该信息才能正确呈现,如果您将其从 URL 中删除,则该信息将丢失。考虑到直接从 URL 打开页面是可能的,无论是在 Web 上还是使用深度 link。如果所需的数据不可用,那么它将无法工作。

在你的情况下,你似乎传递了一个完整的用户对象(也许不是,没有代码很难说)。理想情况下,这个对象应该在你的全局存储而不是参数中,你应该只在参数中传递用户 ID。然后,您应该使用该 ID 从全局存储中获取完整对象,或者如果尚未获取对象(如果需要)则触发数据获取。

您没有在问题中指定 React Navigation 的版本。在 v5 中,您可以自定义如何将参数字符串化为 URLs,以及如何使用 stringifyparse 选项将它们解析回来:

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

这应该可以帮助您使 URL 看起来更漂亮,并处理参数不是简单字符串的情况。但是,您不能完全省略 URL 中的参数,因为它们是屏幕呈现所必需的数据。

更多详情:https://reactnavigation.org/docs/configuring-links#passing-params

绝对是正确的路径。只是想 post 这个解决方案,因为它是对问题的直接回答,即使不是最可取的。

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;
  }
};

注意:要使用此解决方案,您需要确保每个对象和函数参数都是可选的,否则如果您重新加载页面,将会出现错误。

我从 url 中删除了每个对象和函数,将此自定义 getPathFromState 添加到 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
  },
}