在 App.js 中的 componentDidMount 上重定向到 url

Redirect to url on commponentDidMount in App.js

我正在尝试实现一个功能,当用户登录到应用程序并且他们还没有完成他们的个人资料时,他们应该被重定向到某个 URL,所以他们试图去的任何地方(注销除外)他们应该被重定向到 complete-profile URL.

我正在使用 react-router-dom 包处理路由。

App.js

class App extends Component {
  async componentDidMount() {
    const logged = isLoggedIn();
    if (logged) {
      const completed = await hasCompleted();
      if (!completed) this.props.history.replace("/complete-profile"); //error showing here
    }
  }

  render() {
    return (
      <React.Fragment>
        <NavBar />
        <main className="container">
          <Switch>
            <Route path="/complete-profile" component={CompleteProfile} />
            <Route path="/login" component={Login} />
            <Route path="/register" component={Register} />
            <Route path="/logout" component={Logout} />
            <Route path="/" exact component={Home} />
          </Switch>
        </main>
      </React.Fragment>
    );
  }
}

所以基本上我在 componentDidMount 方法中尝试做的是:我首先检查用户是否登录。然后检查用户是否已完成他们的个人资料,如果没有完成则它应该重定向到 /complete-profile URL.

但是使用此方法时我遇到了 this.props.history.replace 的错误,因为我猜调用此方法时它没有使用任何道具,显示的错误是:

Unhandled Rejection (TypeError): Cannot read property 'replace' of undefined

实施此方法的正确方法是什么?

因为我认为我不应该在每个组件中实施这 4 行代码来检查完整的配置文件。

这种 TypeError 在使用 React 时变得非常熟悉。当您尝试使用来自 "undefined".

对象的方法时,会发生这种情况

你可以确保 this.props.history 不是像这样未定义的:

 if (this.props.history && !completed)
   this.props.history.replace("/complete-profile"); //error showing here

npm 包 'Lodash' 也可用于避免这些并发症。

这只是一个卑鄙的把戏。如果您想转到任何 url(包括 React 或任何其他前端框架),只需执行:

window.location.replace(str)

str 可以是绝对路径,如“https://abcd.com”,也可以是相对路径,如(“/complete-profile”,它将成为 baseurl + “/complete-profile”)

if (logged) {
      const completed = await hasCompleted();
      if (!completed) window.location.replace("/complete-profile"); //error showing here
}

@zacks 方法也有效

在 App 组件中,history 属性不可用(未定义),因为以下属性:

  • 历史
  • 位置
  • 匹配

从 Route 组件传递给它的子组件(CompleteProfile、Home、....)。所以你不能在App组件中使用它们。

相反,您可以创建自己的路由组件:

 class CompleteProfile extends Component {
     state = { 
         completed: false
     };
     async componentDidMount() {
        const logged = isLoggedIn();
        if (logged) {
          const completed = await hasCompleted();
          this.setState({completed});              
         //error showing here
    }
  }
     render() {
       const { component: Component, ...rest } = this.props;
       const { completed } = this.state;

       return (
       <Route {...rest} render={(props) => (
         completed
          ? <Component {...props} />
          : <Redirect to='/complete-profile' />
       )} />
    )
  }
}

并使用它代替这样的路线:

<CompleteProfile path='/' exact component={Home} />

这是您可以根据需要重构代码的总体思路。

查看 Route 组件的说明。例如,您会看到为代码中使用 <Route /> 呈现的每个组件注入了三个道具。 <Route path="/login" component={Login} />这些道具是matchlocationhistory

在您的代码中,应用程序未使用路由呈现。因此,您无权访问这三个注入的道具。这就是为什么你得到历史未定义的错误的原因。

要重定向用户,请改用类似下面的内容,您可以在其中有条件地呈现重定向或 UI,具体取决于数据是否存在。

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      fetchingStatus: true,
      completed: false
    };
  }

  async componentDidMount() {
    const logged = isLoggedIn();
    if (logged) {
      const completed = await hasCompleted();
      if (!completed) this.setState({ fetchingStatus: false, completed: true })
    }
  }

  render() {
    const { fetchingStatus, completed } = this.state;
    // Render nothing, or a spinner as loading indicator
    if (fetchingStatus) return null; // waiting for details...
    // if data was fetched and registeration not completed, render redirect.
    if (!fetchingStatus && !completed) return <Redirect to="/complete-profile" />
    // Render switch and nav.
    return (
      <React.Fragment>
        <NavBar />
        <main className="container">
          <Switch>
            <Route path="/complete-profile" component={CompleteProfile} />
            <Route path="/login" component={Login} />
            <Route path="/register" component={Register} />
            <Route path="/logout" component={Logout} />
            <Route path="/" exact component={Home} />
          </Switch>
        </main>
      </React.Fragment>
    );
  }
}

More on React Router's redirect component here