简体   繁体   中英

My React list item components don't render one at a time

I don't do a lot of React programming anymore, so I hope this one has a simple answer.

I have a mock generator function that returns 3 primes at 2-second intervals. I insert each prime yielded into a list as they are returned. The list does not render until all 3 primes are returned. I'm attaching just the relevant code.

function* testPrimes(addPrime) {
  const primes = [3, 5, 7];
  let time = Date.now();
  let i = 0;
  do {
    const nTime = Date.now();

    if (nTime - time > 2000) {
      yield primes[i++];
      time = nTime;
    }
  } while (i < primes.length);
}

In the parent component, I populate the contained list (which is just divs, actually):

  return (
    <div>
      <div>{appState === RUNNING ? "Running..." : "Stopped"}</div>
      <div className="row">
        {(() => {
          if (appState === RUNNING) {
            for (const prime of testPrimes()) {
              console.log("foo");
              primes.push(<Response {...{ prime, key: prime }} />);
            }
          }
        })()}
        {primes}
      </div>
    </div>
  );

I see the "foo"s printed out at intervals, but the <Response> components are rendered all at once.

Since Javascript is single-threaded, UI rendering is blocked until all primes are yielded. Please use setTimeout() instead for non-UI blocking prime generation. And you shouldn't generate primes in render() function but in componentDidMount() or somewhere else and let the component re-render by updating state.

You can use a Pub-Sub pattern too. Assign event subscription in a useEffect .

// Check this library: https://www.npmjs.com/package/pubsub-js
import pubSub from 'pubsub-js';

function *generator() {
  // This yields primes. 
  // For eg:
  const primes = [2, 3, 5, 7, ...]
  let i = 0;
  while (true) {
    yield primes[i++];
  }
  // You can use your own logic get next prime. 
}


const generatorInstance = generator();

function publishPrimes(time = 2000) {
  const prime1 = generatorInstance.next().value;  
  const prime2 = generatorInstance.next().value;  
  const prime3 = generatorInstance.next().value;  

  // Publish 3 primes
  pubSub.publish('NEXT_PRIMES', [prime1, prime2, prime3]);

  // Use setTimeout to publish next 3 after 2 seconds 
  // instead of waiting for 2 seconds to complete using a
  // while loop, which is a **blocking** operation.
  setTimeout(() => {
    publishPrimes();
  }, time);
}

// Do the following inside a useEffect of a component
pubSub.subscribe('NEXT_PRIMES', (primes) => {
  setResponses([
    ...responses, 
    ...primes.map(p => <Response prime={p} />),
  ])
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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