我正在尝试使用私有路由和上下文向React + Typescript应用添加简单身份验证。我有一个带有按钮的简单登录组件,该组件仅将上下文中的布尔值var authenticated
设置为true。专用路由应检查此变量,如果不正确,则重定向到登录组件,否则显示指定的组件。问题是authenticated
似乎总是错误的,而且我总是被重定向到登录页面。
当我调试它时,我可以看到单击登录按钮时在AuthContextProvider中调用setAuthenticated
函数。但是,如果我随后单击指向私有路由的任何链接,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,则会看到相反的行为,就永远不会看到登录页面。这应该是动态的吗?
答案 0 :(得分:2)
或者,在onClick回调中,设置event.preventDefault()
,使其不提交表单。
答案 1 :(得分:0)
原来的问题是,每次按下登录按钮时,应用程序都会重新加载,因此会丢失AuthContext中的状态。
之所以这样,是因为在我的登录组件中,我在表单中有一个按钮,该按钮会自动提交表单并重新加载页面。
解决方案是删除表单标签,或者在按钮中指定属性type="button"
。