Reputation: 2597
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.
Upvotes: 1
Views: 193
Reputation: 5388
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} />),
])
});
Upvotes: 1
Reputation: 1563
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.
Upvotes: 2