Как бы я использовал React Hooks для замены моего сAuth () HOC? - PullRequest
1 голос
/ 09 июля 2019

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

Основной HOC, который я использовал в приложениях React, - withAuth - в основном это функция, которая проверяет, аутентифицирован ли currentUser (хранится в состоянии Redux), и, если да, для визуализации упакованного компонента.

Вот реализация этого:

import React, { Component } from "react";
import { connect } from "react-redux";

export default function withAuth(ComponentToBeRendered) {
  class Authenticate extends Component {
    componentWillMount() {
      if (this.props.isAuthenticated === false) {
        this.props.history.push("/signin");
      }
    }
    componentWillUpdate(nextProps) {
      if (nextProps.isAuthenticated === false) {
        this.props.history.push("/signin");
      }
    }
    render() {
      return <ComponentToBeRendered {...this.props} />;
    }
  }

  function mapStateToProps(state) {
    return { isAuthenticated: state.currentUser.isAuthenticated };
  }

  return connect(mapStateToProps)(Authenticate);
}

Чего я не вижу, так это как я могу заменить этот HOC хуками, тем более что хуки не запускаются до тех пор, пока не будет вызван метод render. Это означает, что я не смог бы использовать ловушку для того, что раньше было ProtectedComponent (обернутый с withAuth), чтобы определить, следует ли отображать его или нет, так как он уже будет отображен.

Каков новый причудливый способ ловушки для такого сценария?

1 Ответ

2 голосов
/ 09 июля 2019

render ()

Мы можем переосмыслить вопрос «рендерить или не рендерить» чуть-чуть.Метод визуализации будет всегда вызываться до обратных вызовов или методов жизненного цикла.Это справедливо, за исключением некоторых устаревших методов жизненного цикла .

, которые вскоре должны быть реализованы. Таким образом, ваш метод рендеринга (или функциональный компонент) должен обрабатывать все возможные состояния, включая состояния, которые ничего не требуютбыть оказанным.Либо это, либо работа по рендерингу ничего не может быть поднята до родительского компонента.Это разница между:

const Child = (props) => props.yes && <div>Hi</div>;
// ...
<Parent>
  <Child yes={props.childYes} />
</Parent>

и

const Child = (props) => <div>Hi</div>;
// ...
<Parent>
  {props.childYes && <Child />}
</Parent>

Решение о том, какой из них использовать, является ситуативным.

Крючки

Есть способыиспользования хуков для решения тех же проблем, которые делают HOC.Я бы начал с того, что предлагает HOC;способ доступа к пользовательским данным о состоянии приложения и перенаправление на /signin, когда данные означают недопустимый сеанс.Мы можем снабдить обе эти вещи хуками.

import { useSelector } from "react-redux";

const mapState = state => ({
  isAuthenticated: state.currentUser.isAuthenticated
});

const MySecurePage = props => {
  const { isAuthenticated } = useSelector(mapState);

  useEffect(
    () => {
      if (!isAuthenticated) {
        history.push("/signin");
      }
    },
    [isAuthenticated]
  );
  return isAuthenticated && <MyPage {...props} />;
};

Пара вещей, происходящих в примере выше.Мы используем хук useSelector из react-redux для доступа к состоянию, как мы это делали ранее, используя connect, только с гораздо меньшим количеством кода.

Мы также используем полученное нами значениеот useSelector для условного срабатывания побочного эффекта с помощью крючка useEffect.По умолчанию обратный вызов, который мы передаем useEffect, вызывается после каждого рендера.Но здесь мы также передаем массив зависимостей, который сообщает React, что мы хотим, чтобы эффект срабатывал только при изменении зависимости (в дополнение к первому рендеру, который всегда запускает эффект).Таким образом, мы будем перенаправлены, когда isAuthenticated начнет false или станет false.

Хотя в этом примере используется определение компонента, он также работает как пользовательский хук:

const mapState = state => ({
  isAuthenticated: state.currentUser.isAuthenticated
});

const useAuth = () => {
  const { isAuthenticated } = useSelector(mapState);

  useEffect(
    () => {
      if (!isAuthenticated) {
        history.push("/signin");
      }
    },
    [isAuthenticated]
  );
  return isAuthenticated;
};

const MySecurePage = (props) => {
  return useAuth() && <MyPage {...props} />;
};

OneПоследнее, что вы можете задаться вопросом:

const AuthWrapper = (props) => useAuth() && props.children;

, чтобы сделать что-то вроде этого:

<AuthWrapper>
  <Sensitive />
  <View />
  <Elements />
</AuthWrapper>

Вы можете решить, что последний примерподходить для вас, но я бы прочитал это , прежде чем принять решение.

...