Skip to content

Commit

Permalink
Merge pull request #2804 from preactjs/render-from-effect
Browse files Browse the repository at this point in the history
allow rendering from an effect
  • Loading branch information
marvinhagemeister authored Oct 22, 2020
2 parents 005d43d + e5e24af commit 080bc19
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 1 deletion.
8 changes: 8 additions & 0 deletions hooks/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -331,15 +331,23 @@ function afterPaint(newQueueLength) {
* @param {import('./internal').EffectHookState} hook
*/
function invokeCleanup(hook) {
// A hook cleanup can introduce a call to render which creates a new root, this will call options.vnode
// and move the currentComponent away.
const comp = currentComponent;
if (typeof hook._cleanup == 'function') hook._cleanup();
currentComponent = comp;
}

/**
* Invoke a Hook's effect
* @param {import('./internal').EffectHookState} hook
*/
function invokeEffect(hook) {
// A hook call can introduce a call to render which creates a new root, this will call options.vnode
// and move the currentComponent away.
const comp = currentComponent;
hook._cleanup = hook._value();
currentComponent = comp;
}

/**
Expand Down
52 changes: 51 additions & 1 deletion hooks/test/browser/useEffect.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { act } from 'preact/test-utils';
import { createElement, render, Fragment, Component } from 'preact';
import { useEffect, useState, useRef } from 'preact/hooks';
import { setupScratch, teardown } from '../../../test/_util/helpers';
import { useEffect, useState } from 'preact/hooks';
import { useEffectAssertions } from './useEffectAssertions.test';
import { scheduleEffectAssert } from '../_util/useEffectUtil';

Expand Down Expand Up @@ -320,4 +320,54 @@ describe('useEffect', () => {

render(<div>Replacement</div>, scratch);
});

it('support render roots from an effect', async () => {
let promise, increment;

const Counter = () => {
const [count, setCount] = useState(0);
const renderRoot = useRef();
useEffect(() => {
if (count > 0) {
const div = renderRoot.current;
return () => render(<Dummy />, div);
}
return () => 'test';
}, [count]);

increment = () => {
setCount(x => x + 1);
promise = new Promise(res => {
setTimeout(() => {
setCount(x => x + 1);
res();
});
});
};

return (
<div>
<div>Count: {count}</div>
<div ref={renderRoot} />
</div>
);
};

const Dummy = () => <div>dummy</div>;

render(<Counter />, scratch);

expect(scratch.innerHTML).to.equal(
'<div><div>Count: 0</div><div></div></div>'
);

act(() => {
increment();
});
await promise;
act(() => {});
expect(scratch.innerHTML).to.equal(
'<div><div>Count: 2</div><div><div>dummy</div></div></div>'
);
});
});

0 comments on commit 080bc19

Please sign in to comment.