React hooks: не удается перенаправить после редукционного успешного действия - PullRequest
0 голосов
/ 29 марта 2019

Всякий раз, когда я пытаюсь перенаправить после обновления props, я получаю эту ошибку:

Предупреждение. Невозможно выполнить обновление состояния React на отключенном компоненте.Это не работает, но это указывает на утечку памяти в вашем приложении.Чтобы исправить, отмените все подписки и асинхронные задачи в функции очистки useEffect.

Уже пробовал:

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

И это (непосредственно в методе рендеринга):

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

Не знаю, почему 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 голосов
/ 31 марта 2019

Самое простое исправление (при этом также следуя общепринятому шаблону состояния React) состоит в том, чтобы Redirect условно отображался с использованием состояния компонента. Добавьте конструктор с состоянием 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, оно автоматически перенаправляется без выполнения операции!

0 голосов
/ 29 марта 2019

Это может быть анти-паттерном, но я привык обходить эту проблему следующим образом.

В constructor вашего класса переназначьте функцию setState следующим образом

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

Затем в componentWillUnmount установите логическое значение true, не позволяя setState попытаться обновить состояние:

componentWillUnmount() {
    this.isUnmounted = true;
}

Мне это кажется грязным, так что я давно его не использовал, но он хорошо работает для быстрого исправления.

...