Реакция setTimeout не очищается или обновление компонента после размонтирования - PullRequest
5 голосов
/ 29 марта 2019

У меня есть React.Component, который может быть в другом внутреннем states для анимации, изменения состояния с использованием тайм-аута, что-то вроде: State A -> setTimeout(goToStateB, 2000) -> State B.

Вы можете думать об анимации, как в State A, вы видите сообщение Hello и через 2 секунды в State B вы видите Нажмите X, чтобы начать .

Проблема в том, что иногда происходит сбой с ошибкой: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node..Я использую React: 16.8.4.

Я не могу воспроизвести проблему локально, но я отслеживаю ошибки вживую, и это, кажется, происходит довольно часто.Я знаю, что это проблема с setTimeout, потому что когда я заменил (в аналогичном случае, с той же ошибкой), setTimeout с анимацией anime.js, которая удаляется на componentWillUnmount, проблема исчезла.

Компонент выглядит примерно так:

interface IState { finished: boolean; }

class TestComponent extends React.Component<{}, IState> {
    // constructor, other code, etc.

    private changeState(): void {
        this.setState({
            finished: true
        });

        // I also dispatch some other actions to the store, which might result in re-rendering of other components.
    }

    public componentDidMount(): void {
        this.changeState = this.changeState.bind(this); // This is also something really strange, if I bind in the constructor instead of in componentDidMount, the `this` value is different/wrong. So `this` in constructor is referring to a different element than `this` in comonentDidMount ??
        this.timeout = window.setTimeout(this.changeState, 2000);
    }

    public componentWillUnmount(): void {
        window.clearTimeout(this.timeout);
    }

    public render(): JSX.Element {
        return <div>
            {!this.state.finished ? 'Welcome!' : 'Press X to start.'}
        </div>;
    }
}

Это выглядит как-то, даже если тайм-аут должен быть очищен на componentWillUnmount, он не всегда очищается, или он очищается слишком поздно.

Есть идеи, как решить проблему или как продолжить отладку, что не так и почему происходит эта конкретная removeChild ошибка?

Вот (к сожалению минимизированная) трассировка стека: NotFoundError
Не удалось выполнить «removeChild» на «Узле»: удаляемый узел не является дочерним по отношению к этому узлу.

enter image description here

Некоторые дополнительные сведения о последних вызовах, которые вызывают ошибку.Похоже, что что-то во внутренних органах React что-то делает с тайм-аутами / тайм-аутами: enter image description here

...