Проблема
Я пытаюсь использовать Реагировать на границы ошибок , чтобы заблокировать контент для пользователей, не вошедших в систему.
У меня есть«рабочее» решение, но я не понимаю, почему мой взлом заставил его работать Может ли кто-нибудь помочь мне разобрать, что я делаю неправильно?
Общая теория того, что я делаю
Насколько я понимаю ...
У меня есть компонент, который находится в моем приложении и оборачивает основной блок контента (не основной nav tho).Он использует componentDidCatch
, чтобы поймать любой accessDenied
брошенный и перенаправить пользователя на экран входа в систему.
У меня есть HOC, который может использовать любой контейнер, чтобы ограничиться только авторизованными пользователями.Он проверяет текущее состояние isAuthenticated
в магазине и перенаправляет пользователя на страницу входа, если это не так.
Если вы попытаетесь перейти на страницу с ограниченным доступом, HOC (EnsureAuthenticatedConnector
) выдает ошибку, которая всплывает и перехватывается AuthBarrier
.
Так в чем проблема?
Как показано ниже, этот код работает.Но у меня локальное состояние установлено на AuthBarrier
.Это ничего не делает.
Если я удаляю this.setState({ hasError: true });
, он ломается.
URL-адрес изменяется, отображается панель навигации (она находится за пределами границы ошибки), но основной экран просто белый.
Страница входа никогда не появляется.Что делает setState
, не используется?
Мой код
AuthBoundary.js - Часть 1 Функция проверки подлинности
МойHOC ожидает компонент, однако так же connect
, и оба они являются функциями ( ref ).Чтобы решить эту проблему, мы объединяем их с подключением.
EnsureAuthenticatedConnector
должен стоять на первом месте (так как нам нужен доступ к реквизиту, а не к элементу его обертки), поэтому у нас есть функция двойной стрелки, поэтому она получает доступ как к компоненту, так и к реквизиту (эточасть, в которой я опасен).
const accessDenied = {};
const EnsureAuthenticatedConnector = ComposedComponent => props => {
if (!props.isAuthenticated) {
console.log("This console fires twice, but only when an error is thrown in here.");
throw accessDenied;
}
return <ComposedComponent {...props} />;
};
const mapStateToPropsEnsureAuth = state => {
return {
isAuthenticated: state.auth.isAuthenticated,
};
};
const connectedEnsureAuth = compose(
// These are both single-argument HOCs
connect(
mapStateToPropsEnsureAuth,
null
),
EnsureAuthenticatedConnector
);
...
export { ConnAuthBarrier, connectedEnsureAuth };
AuthBoundary.js - Часть 2 Auth Catching element
class AuthBarrier extends Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
children: PropTypes.node.isRequired
};
constructor(props) {
super(props);
this.state = {
hasError: false
};
}
// Catch child errors if they're access denied.
componentDidCatch(error) {
if (error === accessDenied) {
// For reasons unknown removing this line
// causes this to break.
// This makes no sense, because I don't use this anywhere...
this.setState({ hasError: true });
this.props.dispatch(push("/login"));
}
}
render() {
// We do nothing clever always render the
// children
return this.props.children;
}
}
const ConnAuthBarrier = connect()(AuthBarrier);
RestrictedPage.js
import { connectedEnsureAuth} from "components/AuthBoundary";
const RestrictedPage = () => {
return (
<div>
<h1>This content is TOP SECRET</h1>
</div>
);
};
RestrictedPage.displayName = "RestrictedPage";
const AuthRestrictedPage = connectedEnsureAuth(RestrictedPage);
export default AuthRestrictedPage;
Полный консольный журнал ошибок
Консольный журнал при полном рендеринге.
При удалении setState
также запускается следующая строка: Warning: AuthBarrier: Error boundaries should implement getDerivedStateFromError(). In that method, return a state update to display an error message or fallback UI.
Соответствующие модули
- «реагировать»: «^ 16.7.0»,
- «реагировать-избыточно»: «^ 6.0.0»,
- «реагировать-маршрутизатор»: «^ 4.3.1",
- " подключен-реагирует-маршрутизатор ":" ^ 6.2.2 ",