【问题标题】:ReactJs: PrivateRoute component gets called twiceReactJs:PrivateRoute 组件被调用两次
【发布时间】:2021-09-16 06:24:36
【问题描述】:

我有这个用于管理身份验证的 privateRoute 组件:

const PrivateRoute = ({ component: Component, auth, ...rest }) => {
  // This gets logged twice when I navigate in the app
  // Using history.push("/url")
  // And gets logged once when I type the url and hit enter on the browser
  console.log(
    "===============INSIDE PrivateRoute Component========================"
  );
  return (
    <Route
      {...rest}
      render={(props) =>
        auth.isAuthenticated === true ? (
          <Component {...props} />
        ) : (
          <Redirect to="/login" />
        )
      }
    />
  );
};

奇怪的是,当我在应用程序中导航时,该组件被记录了两次。例如,当我点击触发此代码的按钮时:

this.props.history.push("/edit-page-after-login");

我在 App.js 中有这个:

    <PrivateRoute
      path="/edit-page-after-login"
      component={EditProfileAfterLogin}
    />

我有一个在该路由中呈现的组件:

export default class EditProfileInSettings extends Component {
  componentDidMount() {
    console.log(
      "???? ~ file: EditProfileInSettings.js ~ line 5 ~ EditProfileInSettings ~ componentDidMount ~ componentDidMount"
    );
  }
  render() {
    return <div>Test</div>;
  }
}

因此,当我使用 history.push 导航到该组件时,会记录下来:

===============INSIDE PrivateRoute 组件=========================
??? ~ 文件:EditProfileInSettings.js ~ 第 5 行 ~ EditProfileInSettings ~ componentDidMount ~ componentDidMount
===============INSIDE PrivateRoute 组件========================

由于某些奇怪的原因,PrivateRoute 组件被称为 TWICE,这导致我尝试实现的逻辑出现一些问题。

但是,当我在浏览器中写入 url 并输入时,它的行为是正确的,它只会被称为 ONCE

===============INSIDE PrivateRoute 组件=========================
??? ~ 文件:EditProfileInSettings.js ~ 第 5 行 ~ EditProfileInSettings ~ componentDidMount ~ componentDidMount

知道这里发生了什么吗?


编辑 1: 我注意到这个错误只发生在我对组件内的后端进行 API 调用时:

class PrivateRouteTestComponent extends Component {
  componentDidMount() {
    console.log("PrivateRouteTestComponent.componentDidMount is called!");
    // If I comment this out, the problem will not occur.
    // It only occurs with this line
    // It does an API call to the backend to get user profile
    this.props.getAuthenticatedUserProfile();
  }
  render() {
    return (
      <div>
        <button
          onClick={() => {
            this.props.history.push("/videos-page");
          }}
        >
          Home
        </button>
        <h6>Private route test component</h6>
      </div>
    );
  }
}

编辑2:我终于找到了为什么会出现这个错误。调用一个向商店分派东西的函数将更新PrivateRoute,因此它将再次被调用:

class PrivateRouteTestComponent extends Component {
  componentDidMount() {
    console.log("PrivateRouteTestComponent.componentDidMount is called!");
    // This doesn't cause the problem
    testBackendCall();
    // This causes the problem
    // Because it dispatches an action to the store
    // So PrivateRoute gets updated
    this.props.testBackendCallThatDispatchesSomethingToTheStore();
  }
  render() {
    return (
      <div>
        <button
          onClick={() => {
            this.props.history.push("/videos-page");
          }}
        >
          Home
        </button>
        <h6>Private route test component</h6>
      </div>
    );
  }
}

【问题讨论】:

标签: javascript reactjs redux react-router react-router-dom


【解决方案1】:

您正在混合功能组件和基于 React 类的组件,并希望 PrivateRoute 中的日志记录和 EditProfileInSettings 中的日志记录在渲染周期的同一时刻完成 - 但事实并非如此。

EditProfileInSettings 中,您登录安装阶段 (componentDidMount),这在组件的渲染中发生一次(如果未卸载)。

PrivateRoute 中,您登录渲染阶段(认为相当于render 上的类Component),每次React 需要更新您的组件时都会发生这种情况,因为它的道具正在改变。

如果您希望两个日志记录相同,请将您的日志记录放在PrivateRoute 上的useEffect(),或者将您的日志记录放在EditProfileInSettings 上的render()


然后,要知道为什么你的功能组件被渲染两次,记录你所有的 props 并找出两个循环之间的差异。

【讨论】:

    【解决方案2】:

    这就是解决我的问题的方法。仅在挂载时使用 React 钩子在功能组件中执行代码。

    const PrivateRoute = ({ component: Component, auth, ...rest }) => {
      React.useEffect(() => {
        // EXECUTE THE CODE ONLY ONCE WHEN COMPONENT IS MOUNTED
      }, []);
      return (
        <Route
          {...rest}
          render={(props) =>
            auth.isAuthenticated === true ? (
              <Component {...props} />
            ) : (
              <Redirect to="/login" />
            )
          }
        />
      );
    };
    

    【讨论】:

      猜你喜欢
      • 2017-04-02
      • 2018-05-18
      • 2022-01-19
      • 2019-06-01
      • 2020-05-08
      • 2021-04-27
      • 2016-04-01
      • 2012-05-05
      • 2017-01-19
      相关资源
      最近更新 更多