Перенаправить на url на commponentDidMount в 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 - это: сначала проверьте, вошел ли пользователь в систему. Затем проверьте, завершил ли пользователь свой профиль, и если он не завершен, он должен перенаправить URL /complete-profile ,

Но с этим методом я сталкиваюсь с ошибкой с this.props.history.replace потому что он не принимает никаких реквизитов, когда этот метод получает вызов Я думаю, и ошибка, которая отображается, такова:

Unhandled Rejection (TypeError): невозможно прочитать свойство «заменить» неопределенного

Каков правильный способ реализации этого?

Потому что я не думаю, что я должен реализовать эти 4 строки проверки кода для завершенного профиля в каждом отдельном компоненте.

Всего 4 ответа


В компоненте App атрибут истории недоступен (неопределен), поскольку следующие реквизиты:

  • история
  • место нахождения
  • матч

передаются от компонента Route к его дочерним элементам (CompleteProfile, Home, ....). Поэтому вы не можете использовать их в компоненте App.

Вместо этого вы можете создать свой собственный компонент Route:

 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' />
       )} />
    )
  }
}

и используйте его вместо Route следующим образом:

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

Это общая идея, по которой вы можете реорганизовать код так, как хотите.


Посмотрите описание компонента Route . Вы увидите, что для каждого компонента, который отображается с помощью <Route /> в вашем коде, для каждого компонента добавляются три реквизита. <Route path="/login" component={Login} /> Эти реквизиты match history location

В вашем коде приложение не отображается с помощью маршрута. Из-за этого у вас нет доступа к этим трем введенным реквизитам. Вот почему вы получаете ошибку, что история не определена.

Чтобы перенаправить пользователя, используйте вместо него то, что указано ниже, где вы условно визуализируете перенаправление или пользовательский интерфейс в зависимости от наличия данных.

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

Подробнее о компоненте перенаправления React Router здесь


Этот тип TypeError становится очень знакомым при работе с React. Это происходит, когда вы пытаетесь использовать методы из объекта, который является «неопределенным».

Вы можете убедиться, что this.props.history не определено так:

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

Упаковка npm «Lodash» также может быть полезна для предотвращения таких осложнений.


Это просто дешевый трюк. Если вы хотите перейти на любой URL-адрес (в том числе реагировать или любой другой интерфейс), просто выполните:

window.location.replace(str)

str может быть абсолютным путем, как « https://abcd.com », или относительный путь («/ полный профиль», который станет baseurl + «/ full-profile»)

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

Также метод @zacks также работает


Есть идеи?

10000