Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/401.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 反应路由器渲染导致卸载_Javascript_Reactjs_React Router - Fatal编程技术网

Javascript 反应路由器渲染导致卸载

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

我正试图从我的顶级组件中实现经过身份验证的路由(根据React router文档)和动态主题(基本上,当选择菜单项时,主题会改变,但不会发生重定向)-这意味着我的顶级组件中需要少量的状态管理

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
    。如本答案所示,在顶层定义
    PrivateRoute
    。现在工作正常,谢谢,但我注意到,这样做后,路由器不会在用户登录后将用户推回到以前的URL<代码>道具.历史记录
    存在,但除非我添加我不想添加的
    强制刷新
    ,否则不会发生重定向。有什么想法吗
    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;