简体   繁体   English

React:在componentDidMount内部的条件setTimeout中更新状态不会重新加载组件

[英]React: Updating state in a conditional setTimeout inside componentDidMount does not reload the component

EDIT: I figured out the problem shortly after posting this. 编辑:发布此消息后不久,我发现了问题。 See my answer below. 请参阅下面的答案。

I'm really stumped as to why my component won't reload after updating the state. 我真的很困惑为什么更新状态后我的组件不会重新加载。 This is the code for the component in full (minus the imports/export), with annotations: 这是完整的组件代码(减去导入/导出),带有注释:

class About extends Component {
    state = {
        introIsRunning: true,
        animationStep: 1,
        indent: 0,
        steps: {
            1: ["placeholder"],
            2: ["placeholder"],
            3: ["placeholder"],
            4: ["placeholder"],
            5: ["placeholder"],
            6: ["placeholder"],
        },
        content: [],
    };

My goal is to show a new line of content every five seconds until I reach the end of the steps, at which point I stop. 我的目标是每五秒钟显示一次新的内容行,直到到达步骤的结尾,然后停止。

Before I make any state changes, I check to make sure if introIsRunning is true. 在进行任何状态更改之前,请检查以确保introIsRunning是否为true。 Then I check to see if we've reached the end of the steps; 然后,我检查是否已经完成了步骤; if so, I set introIsRunning to false which will prevent anymore state changes. 如果是这样,我将introIsRunning设置为false,这将防止状态更改。

(Looking at this again, I see it's pretty redundant to have the boolean and the animationStep check when I can just check for the animationStep and leave it at that. I can't see why that would be the problem though, so moving on...) (再次查看此内容,当我只需要检查animationStep 并将其留在那儿时,我发现对boolean animationStep进行检查是非常多余的。尽管如此,我看不到为什么会是问题,所以继续。 ..)

    componentDidMount = () => {
        if (this.state.introIsRunning) {
            if (this.state.animationStep > 6 {
                this.setState({ introIsRunning: false });
            }

If this is the first step, I don't want any delay before displaying the first line. 如果这是第一步,那么我希望在显示第一行之前没有任何延迟。 But if at least the first line has already been returned, I want to wait 5 seconds before adding the next. 但是,如果至少第一行已经返回,我想等待5秒再添加下一行。 However, because zero delay would trigger an immediate state change which could potentially cause issues, I've added a 5 second delay to the first line rendering just to make sure that wasn't causing my issue. 但是,由于零延迟会立即触发状态更改,这可能会导致问题,所以我在第一行渲染中添加了5秒的延迟,以确保不会引起问题。

            let animationDelay = 5000;
            if (this.state.animationStep > 1) {
                animationDelay = 10000;
            }

            console.log('state before timeout:', this.state);

The 'state before timeout' console log shows animationStep: 1, and content is an empty array. “超时前的状态”控制台日志显示animationStep:1,内容为空数组。 As expected. 如预期的那样。

After the prescribed delay, I update the state with the correct step's content and increment the step so that on the next iteration, it'll load step 2 and advance to 3, etc. 在指定的延迟之后,我用正确步骤的内容更新状态,并增加步骤,以便在下一次迭代时,它将加载步骤2并前进至3,依此类推。

setupContent just adds a new object with the appropriate content to the state's content array, which gets used in the render method to build out the actual component. setupContent只是将带有适当内容的新对象添加到状态的content数组中,该对象在render方法中用于构建实际组件。

            setTimeout(() => {
                this.setState({
                    content: this.setupContent(this.state.steps[this.state.animationStep]),
                    animationStep: this.state.animationStep + 1,
                });
            }, animationDelay);

            // debugging
            setTimeout(() => {
                console.log('why am I still here? state is:', this.state);
            }, 15000);
        }
    }

    setupContent = content => {
        let updatedContent = [...this.state.content];

        const id = "line_" + this.state.animationStep;

        updatedContent.push({
            id: id,
            number: this.state.animationStep,
            indent: this.state.indent,
            content: content,
        });
    }

The 'why am I still here?' “为什么我还在这里?” console log actually shows the correctly updated state. 控制台日志实际上显示正确更新的状态。 animationStep is now 2, and the content array contains one object built to setupContent's specifications. animationStep现在为2,内容数组包含一个根据setupContent规范构建的对象。

    render() {
        return (
            <div className="container">
                {this.state.content.map(line => (
                    <Line
                        key={line.id}
                        id={line.id}
                        number={line.number}
                        indent={line.indent}
                    >
                        {line.content}
                    </Line>
                ))}
            </div>
        );
    }
}

This correctly turns my content object into a functional Component which is rendering how I want it to. 这样可以将我的内容对象正确地转换为功能组件,该组件正在呈现我想要的样子。 However, it just never advances to the next step. 但是,它永远不会前进到下一步。 After correctly, verifiably updating the state, it just sits here. 在正确,可验证地更新状态之后,它就位于此处。 I've searched around and done as much debugging as I can think to do but I really have no earthly idea why the state would update without reloading the component. 我四处搜寻并进行了尽可能多的调试,但是我真的不知道为什么不重新加载组件就可以更新状态。

Wow, I feel really dumb for figuring this out minutes after posting the question, but the problem — of course — was that I was making all those checks in componentDidMount, which only happens once. 哇,我在发布问题后几分钟想出这个问题确实很愚蠢,但是问题-当然-是我在componentDidMount中进行了所有这些检查,只进行了一次。 I moved all the code out of componentDidMount and into its own function, which I now call in componentDidMount and componentDid Update . 我将所有代码移出componentDidMount并移入了自己的函数,现在我将其称为componentDidMount componentDid Update Now it's working as expected. 现在它正在按预期工作。 I should really get a rubber duck... 我真的应该得到一只橡皮鸭...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM