Javascript 反应路由器渲染导致卸载
我正试图从我的顶级组件中实现经过身份验证的路由(根据React router文档)和动态主题(基本上,当选择菜单项时,主题会改变,但不会发生重定向)-这意味着我的顶级组件中需要少量的状态管理Javascript 反应路由器渲染导致卸载,javascript,reactjs,react-router,Javascript,Reactjs,React Router,我正试图从我的顶级组件中实现经过身份验证的路由(根据React router文档)和动态主题(基本上,当选择菜单项时,主题会改变,但不会发生重定向)-这意味着我的顶级组件中需要少量的状态管理 function App() { const [ state, setState ] = React.useState({ current_theme: themes['blue'] }); const [ logged_in, setLoggedIn ] = Re
function App() {
const [ state, setState ] = React.useState({
current_theme: themes['blue']
});
const [ logged_in, setLoggedIn ] = React.useState( !!Cookie.get('JWT') );
function selectTheme( theme ) {
setState({
current_theme: themes[theme]
});
};
return (
<MuiThemeProvider theme={state.current_theme}>
<>
{
logged_in && <Header selectTheme={ selectTheme }/>
}
<AppContainer logged_in={ logged_in }>
<Switch>
<Route exact path='/' component={ Home }/>
<Route exact path='/service_users' component={ ServiceUsers } />
</Switch>
</AppContainer>
</>
</MuiThemeProvider>
);
}
export default App;
Login.js:
function Login( props ) {
const classes = useStyles();
const [ state, setState ] = useState({
username: '',
password: ''
});
const [ loading, setLoading ] = useState( false );
const [ success, setSuccess ] = useState( !!Cookie.get('JWT') );
console.log( 'success: ', success );
function onInputChange( e ) {
setState({ ...state, [e.target.id]: e.target.value });
}
async function loginRequest( e ) {
e.preventDefault();
const { username, password } = state;
//TODO: validation of email/password
if( username.length < 5 || password.length < 5 )
return;
setLoading( true );
const res = await asyncAjax( 'POST', '/login', { username, password } );
setLoading( false );
if( res.status !== 200 )
console.log( 'ERROR' ); //TODO: add error handling
//Store JWT and systems
Cookie.set( 'JWT', `Bearer ${ res.token }`, { path: '/', days: 30 } );
//Use local storage for systems as likely to be much more data
localStorage.setItem( 'SYSTEMS', JSON.stringify( res.login.systems ) );
//Set login status and push user to referrer
props.setLogin();
props.history.push( from );
}
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<HeaderLogo/>
<form className={classes.form} noValidate>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="username"
label="Email Address"
name="username"
autoComplete="username"
autoFocus
onChange={ onInputChange }
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
onChange={ onInputChange }
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
onClick={ loginRequest }
>
{
loading ? (
<CircularProgress
color='inherit'
size={ 25 }
style={{ color: '#FFF' }}
/>
) : (
'Login'
)
}
</Button>
<Grid container>
<Grid item xs>
<Link href="#" variant="body2">
Forgot password?
</Link>
</Grid>
</Grid>
</form>
</div>
</Container>
);
}
export default Login;
功能登录(道具){
const classes=useStyles();
常量[状态,设置状态]=使用状态({
用户名:“”,
密码:“”
});
const[loading,setLoading]=useState(false);
const[success,setSuccess]=useState(!!Cookie.get('JWT');
console.log('success:',success);
输入更改功能(e){
setState({…state[e.target.id]:e.target.value});
}
异步函数登录请求(e){
e、 预防默认值();
const{username,password}=state;
//TODO:验证电子邮件/密码
如果(username.length<5 | | password.length<5)
返回;
设置加载(真);
const res=await asyncjax('POST','/login',{username,password});
设置加载(假);
如果(恢复状态!==200)
console.log('ERROR');//TODO:添加错误处理
//存储JWT和系统
set('JWT','Bearer${res.token}',{path:'/',days:30});
//对于可能包含更多数据的系统,请使用本地存储
setItem('SYSTEMS',JSON.stringify(res.login.SYSTEMS));
//设置登录状态并将用户推送到推荐人
setLogin();
道具。历史。推(从);
}
返回(
{
装货(
) : (
“登录”
)
}
忘记密码了?
);
}
导出默认登录;
我的问题是,我该如何解决这个问题?我认为问题是由于受保护路由是从函数生成的,导致父函数中的状态更改/重新呈现导致函数重新运行并返回新组件。那么,如何在函数外部呈现这些受保护的路由/而不重新呈现导致卸载/重新装载它们
编辑:现在可以了-谢谢。但是,现在登录成功后,用户不会从登录组件重定向到上一页(至少在添加修复程序之前,这部分工作正常)props.history
存在并且没有错误,但是URL不会更改,除非我将forceRefresh
添加到路由器,我无法执行此操作
我已经编辑了更新的代码块,并从Login.js添加了登录功能
那么,如何在外部渲染这些受保护的路由呢
功能/没有重新呈现导致卸载/重新装载
我不确定这是问题的根源,但您是否尝试在
组件之外构建
组件
大概是这样的:
function App() {
const [ state, setState ] = React.useState({
current_theme: themes['blue']
});
const [ logged_in, setLoggedIn ] = React.useState( !!Cookie.get('JWT') );
function selectTheme( theme ) {
setState({
current_theme: themes[theme]
});
};
function login() {
setLoggedIn( true );
}
return (
<MuiThemeProvider theme={state.current_theme}>
<>
{
logged_in && <Header selectTheme={ selectTheme }/>
}
<AppContainer logged_in={ logged_in }>
<Switch>
<PrivateRoute exact path='/' component={ ServiceUsers } logged_in={logged_in}, log_in={login}/>
<PrivateRoute exact path='/service_users' component={ ServiceUsers } logged_in={logged_in}, log_in={login} />
<Route exact path='/login' render={ ( props ) => <Login { ...props } setLogin={ login.bind( this ) }/> } />
</Switch>
</AppContainer>
</>
</MuiThemeProvider>
);
}
function PrivateRoute({ component: Component, logged_in, log_in, ...rest }) {
return (
<Route
{ ...rest }
render={ props => {
return props.logged_in ? (
<Component { ...props } />
) : (
<Redirect
to={{
pathname: '/login',
setLogin: log_in.bind( this ),
state: { from: props.location, test: 'test' }
}}
/>
)
}
}
/>
);
}
export default App;
函数应用程序(){
常量[状态,设置状态]=React.useState({
当前主题:主题['blue']
});
const[logged_in,setLoggedIn]=React.useState(!!Cookie.get('JWT');
功能选择主题(主题){
设定状态({
当前主题:主题[主题]
});
};
函数登录(){
setLoggedIn(真);
}
返回(
{
已登录&&
}
} />
);
}
函数privaterout({component:component,logged_-in,log_-in,…rest}){
返回(
{
返回道具。是否已登录(
) : (
)
}
}
/>
);
}
导出默认应用程序;
编辑: 既然你已经提到了,我想解决你的路由重定向问题。我认为问题在于
history
对象不能独立于函数访问。我不知道为什么它以前是可用的,因为您没有共享更多的代码和分解的结构
无论如何,以下步骤应允许您使用独立的导出历史对象:
- 安装历史记录软件包:
npmi--保存历史记录
组件所在的文件中:
从“历史记录/createBrowserHistory”导入createHistory
const history=createHistory()代码>
- 使用
而不是Router
:BrowserRouter
从'react Router'导入{Router}代码>
- 将
对象作为道具传递给历史记录
:路由器
存在,但除非我添加我不想添加的是,这将是问题的根源。在
内部定义App
将导致PrivateRoute
成为新的组件类型,每次重新呈现PrivateRoute
。如本答案所示,在顶层定义App
。现在工作正常,谢谢,但我注意到,这样做后,路由器不会在用户登录后将用户推回到以前的URL<代码>道具.历史记录PrivateRoute
,否则不会发生重定向。有什么想法吗强制刷新
function App() { const [ state, setState ] = React.useState({ current_theme: themes['blue'] }); const [ logged_in, setLoggedIn ] = React.useState( !!Cookie.get('JWT') ); function selectTheme( theme ) { setState({ current_theme: themes[theme] }); }; function login() { setLoggedIn( true ); } return ( <MuiThemeProvider theme={state.current_theme}> <> { logged_in && <Header selectTheme={ selectTheme }/> } <AppContainer logged_in={ logged_in }> <Switch> <PrivateRoute exact path='/' component={ ServiceUsers } logged_in={logged_in}, log_in={login}/> <PrivateRoute exact path='/service_users' component={ ServiceUsers } logged_in={logged_in}, log_in={login} /> <Route exact path='/login' render={ ( props ) => <Login { ...props } setLogin={ login.bind( this ) }/> } /> </Switch> </AppContainer> </> </MuiThemeProvider> ); } function PrivateRoute({ component: Component, logged_in, log_in, ...rest }) { return ( <Route { ...rest } render={ props => { return props.logged_in ? ( <Component { ...props } /> ) : ( <Redirect to={{ pathname: '/login', setLogin: log_in.bind( this ), state: { from: props.location, test: 'test' } }} /> ) } } /> ); } export default App;