React挂钩:redux成功操作后无法重定向

时间:2019-03-29 18:41:55

标签: reactjs redux react-redux react-router-v4 react-hooks

每次更新props后尝试重定向时,都会出现此错误:

  

警告:无法在已卸载的组件上执行React状态更新。这是空操作,但它表明应用程序中发生内存泄漏。要修复,请取消使用useEffect清理功能中的所有订阅和异步任务。

已经尝试过:

React.useEffect(() => {
    if (props.user) {
        props.history.push("/admin/me");
    }
}, [props.user]);

这(直接在render方法中):

if (props.user) {
    return <Redirect to="/admin/me" />
}

不知道为什么卸载组件后redux会触发更新。我认为这就是问题所在。

如何在卸载组件之前退订Redux更新?

[编辑]

这是有问题的组件

export interface Props extends WithStyles<typeof styles>, RouteComponentProps, React.StatelessComponent, InjectedNotistackProps {
    enqueueSnackbar: (a: any, b: any) => any;
    login: (u: User) => any;
    auth: AuthState;
    api: ApiManager;
};

const LoginPage = (props: Props) => {
    const { classes } = props;

    const api = props.api;
    const [email, setEmail] = React.useState("");
    const [password, setPassword] = React.useState("");


    const onSubmit = (e: React.FormEvent) => {
        e.preventDefault();
        if (!email || !password) {
            return;
        }

        const user = new User({ email, password });

        props.login(user)
            .then(function success(resp: User) {
                api.setToken(resp.token);
            });
    }

    React.useEffect(() => {
        if (props.auth.user && props.auth.user.token) {
            // return <Redirect to="/profile/me" />  This does not work here...          
            props.history.push("/profile/me");
        }
    }, [props.auth.user]);

    return (
        <main className={classes.main}>
            <CssBaseline />

            <form className={classes.form} onSubmit={onSubmit}>
                <Input onChange={e => setEmail(e.target.value)} name="email" />

                <Input onChange={e => setPassword(e.target.value)} name="password" />

                <Button type="submit">
                    Sign in
                </Button>
            </form>

        </main>
    );
}

const stateToProps = (state: AppState) => ({
    auth: state.auth || { token: undefined, user: null }
});

const actionToProps = (dispatch: Dispatch) => ({
    login: (user: User): Promise<User> => {

        dispatch(createLoginStartAction("start"));
        return user.login()
            .then(function (loggedInUser: User) {
                    // This seems to be dispatched after the redirect or something!
                    dispatch(createLoginSuccessAction(loggedInUser)); 
                    return loggedInUser;
                });
    }
});

export default connect(stateToProps, actionToProps)(
    withStyles(styles)(
        withSnackbar(LoginPage)
    )
);

事实证明它确实重定向了,问题在于它可以重新登录。为什么!?!?

2 个答案:

答案 0 :(得分:0)

这可能是一种反模式,但是我过去常常这样解决这个问题。

在您班级的constructor中,像这样重新分配setState函数

const originSetState = this.setState.bind(this);
this.setState = ( ...args ) => !this.isUnmounted&&originSetState(...args);

然后在componentWillUnmount中将布尔值设置为true,以防止setState尝试更新状态:

componentWillUnmount() {
    this.isUnmounted = true;
}

这对我来说很脏,所以我已经有一段时间没有使用它了,但是它可以快速解决问题。

答案 1 :(得分:0)

最简单的解决方法(同时也遵循常规的React状态模式)是使用组件的状态有条件地呈现重定向。添加状态为this.state = {isUser: false}的构造函数,并将{this.state.isUser && <Redirect to="/admin/me" />}添加到</main>之前的渲染方法的底部。最后更改

if (props.user) {
    return <Redirect to="/admin/me" />
}

if (props.user) {
    this.setState({isUser: true);
}

其结果遵循常规的React模式,当状态更改为true时,它将自动重定向,而无需执行无操作!