簡體   English   中英

更改document.body,修改React state 再次更改body

[英]Change document.body, modify React state and change body again

我想在用戶單擊按鈕時更改主體的 CSS class,並在handleClick中定義的操作完成時將其反轉。

我有以下handleClick function:

handleClick = data => {
    document.body.classList.add('waiting');
    this.setState({data}, () => document.body.classList.remove('waiting'));
}

我希望它能以下列方式工作:

  1. 添加waiting class 到正文
  2. 更改組件 state
  3. 從正文中刪除waiting class

但它不是那樣工作的。 為了讓它工作,我必須將handleClick function 更改為如下所示:

handleClick = data => {
    document.body.classList.add('waiting');
    setTimeout(() => this.setState({data}, () => document.body.classList.remove('waiting')))
}

我想知道為什么會這樣。 我知道setTimeout正在“延遲”執行this.setState但據我所知this.setState本身是異步的所以它不應該自己延遲嗎? 這是否意味着更改document.body.classList也是異步的並且它的執行比this.setState的執行延遲更多?

但它不是那樣工作的。

它確實如此,但這並不意味着您在瀏覽器 window 中看到任何變化。:-)您所做的正是您所描述的:在 state 更改之前設置 class,進行 state 更改,並在state 零錢。

 const {useState} = React; class Example extends React.Component { state = { counter: 0, }; handleClick = () => { console.log("Adding class"); document.body.classList.add('waiting'); // NOTE: Normally this should use the callback form of a state setter, // rather than assuming that `this.state.counter` is up-to-date. But // I wanted to keep using the same type of call as you were console.log("Setting state"); this.setState({counter: this.state.counter + 1}, () => { console.log("Removing class"); document.body.classList.remove('waiting'); }); }; componentDidUpdate() { console.log("componentDidUpdate"); } render() { console.log(`render, counter = ${this.state.counter}`); return <div> <div>{this.state.counter}</div> <input type="button" value="Click Me" onClick={this.handleClick} /> </div>; } }; ReactDOM.render(<Example />, document.getElementById("root"));
 <div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

但是狀態更改后的回調可能會在 DOM 更新之前發生,並且可能會在頁面顯示更新以說明body類的更改之前單獨發生。

...但據我所知this.setState本身是異步的所以它不應該自己延遲...

state 更新是異步的,是的,但可以非常主動地完成(它甚至可以是一個微任務,在當前任務完成后立即運行,這是在瀏覽器更新 class 更改的頁面顯示之前——或者不是,它是一個React 的實現細節)。

這是否意味着更改document.body.classList也是異步的並且它的執行比this.setState的執行延遲更多?

不,變化是同步的,但是直到下一次瀏覽器繪制顯示時你才會看到變化,直到當前任務和它所有排隊的微任務完成(或者甚至在那之后;瀏覽器同步到顯示設備的刷新率,因此通常為 60 次/秒 [大約每 16.67 毫秒一次],但對於更高端的顯示器和顯示適配器可能會更高)。

您的setTimeout(/*...*/, 0)技巧是處理此問題的一種常用方法,盡管當該計時器觸發時瀏覽器可能尚未更新顯示(因為再次更新之間通常約為 16.67 毫秒)。 您可以使用requestAnimationFrame掛鈎瀏覽器的頁面顯示更新周期,它會在瀏覽器即將更新顯示之前為您提供回調。 但與(比如)20 毫秒的延遲相比,這可能有點矯枉過正。

處理此問題的另一種方法是立即添加 class 並使用componentDidUpdate安排在下一個 animation 幀刪除它。 但同樣,這可能過於復雜。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM