我如何从我的url中获取appId参数,并将其传递给我的子组件?

问题描述 投票:0回答:1

我有一个App.jsx父组件和一个TopBar.js子组件。我想做的是从url中获取appId参数,然后把它传递给我的TopBar子组件。问题是我不知道如何使用match.params.appId,像CategoryPage (<CategoryPage categoryId = {match.params.categoryId} />),因为我得到了一个错误信息:match is not defined,这似乎是正常的,因为我的子组件没有包含在一个 <Route> 组件。我看了一下文档,我只能找到经典的案例,有没有其他的方法来检索路由参数,比如说把它存储在一个状态中,以便重复使用呢?"先谢谢你的帮助或建议,我是这个项目的新手,我正在逐步整合代码的特殊性。

App.jsx

export default class App extends PureComponent {
  static childContextTypes = {
    apiKEY: PropTypes.string,
    apiURL: PropTypes.string,
    appName: PropTypes.string,
    loginToken: PropTypes.string,
    userId: PropTypes.string,
  };

  constructor(props) {
    super(props);
    const parsed = queryString.parse(window.location.search);
    const state = {
      apiKey: null,
      appName: null,
      fetchApiKeyError: null,
      fetchApiKeyPending: false,
      fetchApiKeyDone: false,
    };
    ['auth_token', 'userId'].forEach((key) => {
      state[key] = parsed[key] || localStorage.getItem(key);
      if (parsed[key]) localStorage.setItem(key, parsed[key]);
    });

    this.state = state;
    this.handleErrorAuth = this.handleErrorAuth.bind(this);
  }

  getChildContext() {
    const {
      auth_token: loginToken, userId, apiKey, appName,
    } = this.state;
    return {
      apiURL: process.env.REACT_APP_API_URL,
      loginToken,
      userId,
      apiKEY: apiKey,
      appName,
    };
  }

  renderRedirect = () => {
    const isLogged = localStorage.auth_token && localStorage.userId;

    // This is a private app, so we need to be logged all time
    if (!isLogged) {
      window.location = `${process.env.REACT_APP_AUTH_URL}?redirect_uri=${window.location}`;
      return null;
    }

    return null;
  }

  fetchApiKey = (appId, authToken) => {
    if (!authToken) return;
    this.setState({ fetchApiKeyPending: true });
    const storageKey = `apiKey_${appId}`;
    const nameStorageKey = `name_${appId}`;
    const apiKey = localStorage.getItem(storageKey);
    const appName = localStorage.getItem(nameStorageKey);
    // ApiKey and appName already in localStorage
    if (apiKey && appName) {
      this.setState({
        fetchApiKeyPending: false,
        fetchApiKeyDone: true,
        apiKey,
        appName,
      });
      return;
    }

    // flush all previous keys
    Object.keys(localStorage)
      .filter((val) => val.indexOf('apiKey_') + 1 || val.indexOf('name_') + 1)
      .forEach((val) => localStorage.removeItem(val));

    // get ApiKey
    fetch(`${process.env.REACT_APP_API_URL}/apps/${appId}/infos`, {
      headers: {
        Authorization: `Bearer ${authToken}`,
      },
    }).then((data) => {
      if (!data.ok) throw new Error(data.status);
      return data;
    })
      .then((data) => data.json())
      .then(({ key, name }) => {
        localStorage.setItem(storageKey, key);
        localStorage.setItem(nameStorageKey, name);
        this.setState({
          fetchApiKeyPending: false,
          fetchApiKeyDone: true,
          fetchApiKeyError: null,
          apiKey: key,
          appName: name,
        });
      })
      .catch((e) => this.setState({
        fetchApiKeyPending: false,
        fetchApiKeyDone: true,
        fetchApiKeyError: e,
        apiKey: null,
        appName: null,
      }));
  };

  getLastAppId = () => {
    const storageKey = Object.keys(localStorage).filter(
      (val) => val.indexOf('apiKey_') + 1,
    )[0];
    return storageKey ? storageKey.split('apiKey_')[1] : null;
  };

  switch = (location) => {
    const {
      fetchApiKeyPending,
      fetchApiKeyDone,
      apiKey,
      auth_token: loginToken,
      fetchApiKeyError,
    } = this.state;

    return (
      <Switch location={location}>
        {apiKey && [
          <Route
            key="1"
            path="/:appId/categories/:categoryId/new_article"
            render={({ match }) => (
              <DefaultLayout>
                <NewArticlePage categoryId={match.params.categoryId} />
              </DefaultLayout>
            )}
          />,
          <Route
            key="2"
            path="/:appId/articles/:articleId"
            render={({ match }) => (
              <DefaultLayout>
                <ModifyArticlePage articleId={match.params.articleId} />
              </DefaultLayout>
            )}
          />,
          <Route
            key="3"
            path="/:appId/createCategory"
            render={({ match }) => (
              <CenteredLayout
                backButtonProps={{
                  to: `/${match.params.appId}/categories`,
                }}
              >
                <NewCategoryPage />
              </CenteredLayout>
            )}
            apikey
          />,
          <Route
            key="4"
            path="/:appId/categories/:categoryId/modify"
            render={({ match }) => (
              <CenteredLayout>
                <NewCategoryPage categoryId={match.params.categoryId} />
              </CenteredLayout>
            )}
          />,
          <Route
            key="5"
            path="/:appId/categories/:categoryId"
            render={({ match }) => (
              <CenteredLayout
                backButtonProps={{
                  to: `/${match.params.appId}/categories`,
                }}
              >
                <CategoryPage categoryId={match.params.categoryId} />
              </CenteredLayout>
            )}
          />,
          <Route key="6" path="/:appId/categories" component={CategoriesPage} />,
        ]}
        <Route path="/welcome" component={WelcomePage} />
        <Route path="/app_not_found" render={() => <AppNotFoundPage titleKey="press" />} />
        <Route
          path="/:appId/"
          exact={false}
          render={({ match }) => {
            if (fetchApiKeyError) {
              return <Redirect to="/app_not_found" />;
            }
            if (!fetchApiKeyDone || fetchApiKeyPending) {
              return (
                [
                  <OnMountExecuter
                    key="1"
                    execute={this.fetchApiKey}
                    params={[match.params.appId, loginToken]}
                  />,
                  <Loading key="2" style={{ fontSize: 36 }} />,
                ]
              );
            }
            return <Redirect to={`/${match.params.appId}/categories`} />;
          }}
        />
        <Route
          path="/"
          render={() => {
            if (localStorage.auth_token && localStorage.userId) {
              const appId = this.getLastAppId();
              if (appId) {
                return <Redirect to={`/${appId}/categories`} />;
              }
            }
            return <Redirect to="/welcome" />;
          }}
        />
      </Switch>
    );
  };

  handleErrorAuth() {
    this.setState({
      auth_token: null,
      userId: null,
    });
    localStorage.clear();
  }

  renderContent(location) {
    return (
      <HttpsRedirect>
        <IntlProvider locale={language} messages={messages[language]}>
          <div id="container">
            <div id="content-container">
              <AuthorizeChecker onError={this.handleErrorAuth} />
              <UserContextProvider>
                <UserContext.Consumer>
                  {(user) => <TopBar user={user} />}
                </UserContext.Consumer>
                {this.switch(location)}
              </UserContextProvider>
            </div>
          </div>
        </IntlProvider>
      </HttpsRedirect>
    );
  }

  render() {
    return (
      <BrowserRouter>
        <Route
          render={({ location }) => this.renderRedirect(location) || this.renderContent(location)}
        />
      </BrowserRouter>
    );
  }
}
javascript reactjs react-router components
1个回答
0
投票

你可以使用react router创建的上下文从Router组件的任何一个大子组件中访问match对象,它可以在下面找到,context =>router=>match。从那里你可以对它做任何你想做的事情。

你可以在 this.context 在任何基于类的组件中,在一个钩子组件中,你必须使用钩子。useContext

另外,请注意,新版本的react router有一些钩子,可能会对你有所帮助,如useRouteMatchuseParams.

© www.soinside.com 2019 - 2024. All rights reserved.