Невозможно разделить экраны «Выйти» и «Выйти» в React Router + FIrebase - PullRequest
1 голос
/ 15 января 2020

Я работаю над приложением с React + Firebase. Приложение требует аутентификации, чтобы пользователи обращались к своей временной шкале. Поэтому я хочу, чтобы приложение было разделено между LoggedIn экранами и LoggedOut экранами.

В App.js я настроил <Auth />, чтобы экраны требовали аутентификации. Вот так:

function App() {
  return (
    <Provider store={store}>
      <BrowserRouter>
        <div>
          <Switch>
            <Switch>
              <Auth>
                <Route path="/timeline" component={Timeline} />
              </Auth>
            </Switch>
            <Route path="/" component={Home} />
          </Switch>
        </div>
      </BrowserRouter>
    </Provider>
  );
}

export default App;

И добавил Auth.

import React from "react";
import { Redirect } from "react-router-dom";
import firebase from "../config/firebase";

class Auth extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      user: false
    };
  }

  componentDidMount() {
    firebase.auth().onAuthStateChanged(user => {
      if (user) {
        this.setState({ user });
      }
    });
  }

  render() {
    if (!this.state.user) {
      return (
        <div>{this.state.user ? this.props.children : <Redirect to="/" />}</div>
      );
    }
  }
}

export default Auth;

Но это не работает. В нем нет сообщения об ошибке, но я не могу получить доступ к каким-либо компонентам ...

Ответы [ 2 ]

1 голос
/ 15 января 2020

Router Issue

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

Я думаю, вы здесь слишком усложнили компонент приложения. Я бы порекомендовал что-то более похожее на приведенный ниже пример, потому что вашей логике маршрутизации c не нужно заботиться об аутентификации. Вы можете обернуть компонент Timeline компонентом Auth внутри реализации Timeline , и тогда маршрутизатор просто выполнит маршрутизацию, ничего больше.

function App() {
  return (
    <Provider store={store}>
      <BrowserRouter>
        <div>
          <Switch>
            <Route path="/timeline" component={Timeline} />
            <Route path="/" component={Home} />
          </Switch>
        </div>
      </BrowserRouter>
    </Provider>
  );
}

export default App;

Альтернатива, как упомянуто в ссылка выше, это написать свой собственный Switch logi c. Это может позволить вам сохранять все аутентифицированные маршруты видимыми заранее, но вы, возможно, не захотите возиться с этим.

Вам необходимо состояние аутентификации

Как затронуто в ответе Сороу sh у вас также есть проблема с управлением состоянием в компоненте Auth. На данный момент это выглядит так:

  1. Компонент отображается с user = false
  2. Компонент перенаправления отображается, и страница перенаправляется на '/'

Видите ли вы, как никогда нет возможности правильно отрисовать дочерний элемент auth для аутентифицированного пользователя, потому что первоначальный рендеринг всегда будет вызывать перенаправление? Firebase никогда не имеет возможности войти в систему пользователя до того, как он будет перенаправлен.

Чтобы это исправить, вы авторизуетесь, чтобы загрузить страницу в какое-то состояние «аутентификации» и перенаправить пользователя только после того, как узнаете, вошли или нет. Помните, что onAuthStateChanged будет запускаться только после первоначального рендеринга .

Удачи!

1 голос
/ 15 января 2020

В этом случае и вашей структуре аутентификации я рекомендовал вам использовать программную навигацию.

import { withRouter } from "react-router";

class Auth extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      user: false,
      authenticating: true,
    };
  }

  componentDidMount() {
    firebase.auth().onAuthStateChanged(user => {
      if (!user) {
        this.props.history.push('/login');
      } else {
        this.setState({ authenticating: false });
      }
    });
  }

  render() {
    return (
      <div>{authenticating ? <p>Authenticating...</p> : this.props.children}</div>
    );
  }
}

export default withRouter(Auth);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...