Я пытаюсь добавить простую аутентификацию в приложение React + Typescript, используя частные маршруты и контекст. У меня есть простой компонент входа в систему с кнопкой, которая просто устанавливает логическое значение var authenticated
в контексте в значение true. Приватные маршруты должны проверить эту переменную и перенаправить на компонент входа в систему, если это не так, в противном случае показать указанный компонент. Проблема в authenticated
, кажется, всегда ложной, и я всегда перенаправлен на страницу входа.
Когда я отлаживаю его, я вижу, что функция setAuthenticated
в AuthContextProvider вызывается при нажатии кнопки входа в систему. Но если я затем нажму на любую из ссылок на частные маршруты, authenticated
всегда будет ложным.
Вот мой App.tsx:
function App() {
return (
<AuthContextProvider>
<Router>
<Link to="/">Home</Link>
<Link to="/projects">Projects</Link>
<div>
<Route path="/login" component={Login} />
<PrivateRoute path="/" exact component={Home} />
<PrivateRoute path="/projects" component={Projects} />
</div>
</Router>
</AuthContextProvider>
);
}
export default App;
PrivateRoute.tsx:
interface PrivateRouteProps extends RouteProps {
// tslint:disable-next-line:no-any
component: any;
}
const PrivateRoute = (props: PrivateRouteProps) => {
const { component: Component, ...rest } = props;
return (
<AuthContextConsumer>
{authContext => authContext && (
<Route {...rest}
render={ props =>
authContext.authenticated === true ? (
<Component {...props} />
) : (
<Redirect to="/login" />
)
}
/>
)}
</AuthContextConsumer>
);
};
export default PrivateRoute;
AuthContext.tsx:
export interface AuthContextInterface {
authenticated: boolean,
setAuthenticated(newAuthState: boolean):void
}
const ctxt = React.createContext<AuthContextInterface>({
authenticated: false,
setAuthenticated: () => {}
});
export class AuthContextProvider extends React.Component {
setAuthenticated = (newAuthState:boolean) => {
this.setState({ authenticated: newAuthState });
};
state = {
authenticated: false,
setAuthenticated: this.setAuthenticated,
};
render() {
return (
<ctxt.Provider value={this.state}>
{this.props.children}
</ctxt.Provider>
);
}
}
export const AuthContextConsumer = ctxt.Consumer;
Login.tsx:
function Login() {
return (
<AuthContextConsumer>
{({ authenticated, setAuthenticated }) => (
<div>
<p>Login</p>
<form>
<input type="text" placeholder="Username"/>
<input type="password" placeholder="Password"/>
<button onClick={event => {
setAuthenticated(true);
}}>Login</button>
</form>
</div>
)}
</AuthContextConsumer>
);
}
export default Login;
Я подозреваю, что что-то не так с определением состояния в AuthContextProvider. Если я изменю authenticated
здесь на true, я вижу противоположное поведение, я никогда не вижу страницу входа. Должно ли это быть чем-то динамичным?