Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
231 views
in Technique[技术] by (71.8m points)

javascript - React: Expensive computation in useEffect blocking the rendering

When user change the select option, I need to do some time consuming work. While doing this work, I wanna show loading message, but it's not working

import React, { useState, useEffect } from "react";
import "./styles.css";

export default function App() {
  const [a, setA] = useState(1);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    sleep(2000);
    console.log("finish");

    setIsLoading(false);
  }, [a]);
  return (
    <div>
      {isLoading && "loding"}
      <div>
        <button
          onClick={() => {
            setIsLoading(true);
            setA((a) => a + 1);
          }}
        >
          button
        </button>

        <select
          onChange={() => {
            setIsLoading(true);
            setA((a) => a + 1);
          }}
        >
          {[1, 2, 3].map((i) => (
            <option key={i} value={i}>
              {i}
            </option>
          ))}
        </select>
      </div>
    </div>
  );
}

function sleep(d) {
  let t = Date.now();
  while (Date.now() - t <= d);
}

but it's working on button onClick event. It looks so weird! And here is the online demo: https://codesandbox.io/s/modest-pasteur-8vrr0?file=/src/App.js:0-908

question from:https://stackoverflow.com/questions/65940055/react-expensive-computation-in-useeffect-blocking-the-rendering

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You need to give react time to update the screen before starting the sleep/heavy work process.

Set a after a timer:

 setTimeout(() => {
         setA((a) => a + 1);
      }, 50)

This will allow react to udapte screen with loading === true and after that, it will work on the process.

You could also try to use a webworker to offload the work form the main thread to not block the rendering. Check out useWorker.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...