Skip to content

Commit

Permalink
Merge branch 'master' into shared-internals
Browse files Browse the repository at this point in the history
  • Loading branch information
developit committed Jan 7, 2020
2 parents cf55aeb + 5d1dc19 commit d2dcbc2
Show file tree
Hide file tree
Showing 20 changed files with 381 additions and 490 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ addons:
sauce_connect: true

script:
- COVERAGE=true npm run test
- COVERAGE=true FLAKEY=false npm run test
- ./node_modules/coveralls/bin/coveralls.js < ./coverage/lcov.info;

after_success: sizereport --config
479 changes: 29 additions & 450 deletions README.md

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions compat/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ var renderToString;
try {
renderToString = dep(require('preact-render-to-string'));
} catch (e) {
throw new Error(
'You seem to be missing the "preact-render-to-string" dependency.\n' +
'You can add this by using "npm install --save preact-render-to-string@next".'
throw Error(
'renderToString() error: missing "preact-render-to-string" dependency.'
);
}

Expand Down
4 changes: 2 additions & 2 deletions compat/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { Children } from './Children';
import { Suspense, lazy } from './suspense';
import { SuspenseList } from './suspense-list';
import { createPortal } from './portals';
import { render, REACT_ELEMENT_TYPE } from './render';
import { hydrate, render, REACT_ELEMENT_TYPE } from './render';

const version = '16.8.0'; // trick libraries to think we are react

Expand Down Expand Up @@ -100,7 +100,7 @@ export {
version,
Children,
render,
render as hydrate,
hydrate,
unmountComponentAtNode,
createPortal,
createElement,
Expand Down
4 changes: 4 additions & 0 deletions compat/src/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export function render(vnode, parent, callback) {
}
}

return hydrate(vnode, parent, callback);
}

export function hydrate(vnode, parent, callback) {
preactRender(vnode, parent);
if (typeof callback === 'function') callback();

Expand Down
2 changes: 1 addition & 1 deletion compat/src/suspense.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export function lazy(loader) {
prom = loader();
prom.then(
exports => {
component = exports.default;
component = exports.default || exports;
},
e => {
error = e;
Expand Down
25 changes: 25 additions & 0 deletions compat/test/browser/hydrate.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { hydrate } from 'preact/compat';
import { setupScratch, teardown } from '../../../test/_util/helpers';

describe('compat hydrate', () => {
/** @type {HTMLDivElement} */
let scratch;

beforeEach(() => {
scratch = setupScratch();
});

afterEach(() => {
teardown(scratch);
});

it('should render react-style jsx', () => {
const input = document.createElement('input');
scratch.appendChild(input);
input.focus();
expect(document.activeElement).to.equal(input);

hydrate(<input />, scratch);
expect(document.activeElement).to.equal(input);
});
});
103 changes: 103 additions & 0 deletions compat/test/browser/suspense.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1328,4 +1328,107 @@ describe('suspense', () => {
expect(cWUSpy.getCall(0).thisValue).to.eql(suspender);
expect(scratch.innerHTML).to.eql(`<div>conditional hide</div>`);
});

xit('should support sCU=false when un-suspending', () => {
// See #2176 #2125
const [Suspender, suspend] = createSuspender(() => <div>Hello</div>);

render(
<Suspense fallback={<div>Suspended...</div>}>
Text
{/* Adding a <div> here will make things work... */}
<Suspender />
</Suspense>,
scratch
);

expect(scratch.innerHTML).to.eql(`Text<div>Hello</div>`);

const [resolve] = suspend();
rerender();

expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);

Suspender.prototype.shouldComponentUpdate = () => false;

return resolve(() => <div>Hello 2</div>).then(() => {
rerender();
expect(scratch.innerHTML).to.eql(`Text<div>Hello 2</div>`);
});
});

xit('should allow suspended children to update', () => {
const log = [];
class Logger extends Component {
constructor(props) {
super(props);
log.push('construct');
}

render({ children }) {
log.push('render');
return children;
}
}

let suspender;
class Suspender extends Component {
constructor(props) {
super(props);
this.state = { promise: new Promise(() => {}) };
suspender = this;
}

unsuspend() {
this.setState({ promise: null });
}

render() {
if (this.state.promise) {
throw this.state.promise;
}

return 'hello';
}
}

render(
<section>
<Suspense fallback={<div>fallback</div>}>
<Suspender />
<Logger />
</Suspense>
</section>,
scratch
);

expect(log).to.eql(['construct', 'render']);
expect(scratch.innerHTML).to.eql('<section></section>');

// this rerender is needed because of Suspense issuing a forceUpdate itself
rerender();
expect(scratch.innerHTML).to.eql('<section><div>fallback</div></section>');

suspender.unsuspend();

rerender();

/**
* These currently failing assertion shows the issue that we currently unmount
* the suspended tree (unlike react, which adds a display="none") and block any
* further processing on that tree. Thus updates below a suspended Suspense are
* getting lost.
*/
expect(log).to.eql(['construct', 'render', 'render']);

/**
* When the above assertion will hold true we will certainly run into the second issue
* here. The problem is that we do not remove suspensions from an instance of Suspense
* when one of its suspending children no longer throws because of a state
* update.
*/
expect(scratch.innerHTML).to.eql(
'<section><div>Suspender un-suspended</div></section>'
);
});
});
24 changes: 13 additions & 11 deletions debug/test/browser/devtools/renderer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
createContext
} from 'preact';
import { memo, forwardRef, Suspense } from 'preact/compat';
import * as sinon from 'sinon';
import {
createRenderer,
getFilteredChildren
Expand All @@ -28,6 +27,9 @@ import {
SUSPENSE
} from '../../../src/devtools/10/constants';

/* global DISABLE_FLAKEY */
const flakeyIt = DISABLE_FLAKEY ? xit : it;

/** @jsx createElement */

/**
Expand Down Expand Up @@ -116,7 +118,7 @@ describe('Renderer 10', () => {
]);
});

it('should unmount nodes', () => {
flakeyIt('should unmount nodes', () => {
render(
<div>
<span>foo</span>
Expand Down Expand Up @@ -151,7 +153,7 @@ describe('Renderer 10', () => {
]);
});

it('should mount after filtered update', () => {
flakeyIt('should mount after filtered update', () => {
renderer.applyFilters({
regex: [],
type: new Set(['dom'])
Expand Down Expand Up @@ -479,7 +481,7 @@ describe('Renderer 10', () => {
).to.equal(-1);
});

it('should find filtered nodes', () => {
flakeyIt('should find filtered nodes', () => {
renderer.applyFilters({
regex: [],
type: new Set(['dom'])
Expand Down Expand Up @@ -605,7 +607,7 @@ describe('Renderer 10', () => {
]);
});

it('should filter by dom type #1', () => {
flakeyIt('should filter by dom type #1', () => {
renderer.applyFilters({
regex: [],
type: new Set(['dom'])
Expand All @@ -623,7 +625,7 @@ describe('Renderer 10', () => {
]);
});

it('should filter by dom type #2', () => {
flakeyIt('should filter by dom type #2', () => {
renderer.applyFilters({
regex: [],
type: new Set(['dom'])
Expand All @@ -647,7 +649,7 @@ describe('Renderer 10', () => {
]);
});

it('should filter by fragment type', () => {
flakeyIt('should filter by fragment type', () => {
renderer.applyFilters({
regex: [],
type: new Set(['fragment'])
Expand All @@ -672,7 +674,7 @@ describe('Renderer 10', () => {
]);
});

it('should filter on update', () => {
flakeyIt('should filter on update', () => {
renderer.applyFilters({
regex: [],
type: new Set(['dom'])
Expand Down Expand Up @@ -713,7 +715,7 @@ describe('Renderer 10', () => {
]);
});

it('should update filters after 1st render', () => {
flakeyIt('should update filters after 1st render', () => {
renderer.applyFilters({
regex: [],
type: new Set(['dom'])
Expand Down Expand Up @@ -757,7 +759,7 @@ describe('Renderer 10', () => {
]);
});

it('should update filters after 1st render with unmounts', () => {
flakeyIt('should update filters after 1st render with unmounts', () => {
renderer.applyFilters({
regex: [],
type: new Set(['dom'])
Expand Down Expand Up @@ -830,7 +832,7 @@ describe('Renderer 10', () => {
});

describe('getFilteredChildren', () => {
it('should get direct children', () => {
flakeyIt('should get direct children', () => {
const Foo = () => <div>foo</div>;
const Bar = () => <div>bar</div>;

Expand Down
4 changes: 4 additions & 0 deletions hooks/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,7 @@ export function useDebugValue<T>(
value: T,
formatter?: (value: T) => string | number
): void;

export function useErrorBoundary(
callback: () => Promise<void> | void
): [string | undefined, () => void];
18 changes: 18 additions & 0 deletions hooks/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,24 @@ export function useDebugValue(value, formatter) {
}
}

export function useErrorBoundary(cb) {
const state = getHookState(currentIndex++);
const errState = useState();
state._value = cb;
if (!currentComponent.componentDidCatch) {
currentComponent.componentDidCatch = err => {
if (state._value) state._value(err);
errState[1](err);
};
}
return [
errState[0],
() => {
errState[1](undefined);
}
];
}

/**
* After paint effects consumer.
*/
Expand Down
Loading

0 comments on commit d2dcbc2

Please sign in to comment.