Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: preactjs/preact
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 10.19.7
Choose a base ref
...
head repository: preactjs/preact
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 10.20.0
Choose a head ref
  • 5 commits
  • 8 files changed
  • 3 contributors

Commits on Mar 13, 2024

  1. feat: added isMemo to compact to allow compatibility with react-is de…

    …pendant libraries
    ziongh committed Mar 13, 2024
    Copy the full SHA
    1584d4c View commit details

Commits on Mar 19, 2024

  1. Merge branch 'main' into main

    marvinhagemeister authored Mar 19, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    94bfe9d View commit details
  2. Merge pull request #4302 from ziongh/main

    feat: added isMemo to compact to allow compatibility with react-is dependant libraries
    marvinhagemeister authored Mar 19, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    a784a62 View commit details
  3. fix: case where shrinking a list would cause an exception (#4312)

    * yikes
    
    * fix issue
    JoviDeCroock authored Mar 19, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    342b50e View commit details

Commits on Mar 20, 2024

  1. 10.20.0 (#4313)

    * 10.19.8
    
    * 10.20.0
    JoviDeCroock authored Mar 20, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    b820d8b View commit details
Showing with 117 additions and 13 deletions.
  1. +9 −7 compat/src/index.d.ts
  2. +17 −0 compat/src/index.js
  3. +37 −0 compat/test/browser/isMemo.test.js
  4. +1 −1 devtools/src/devtools.js
  5. +2 −2 package-lock.json
  6. +1 −1 package.json
  7. +4 −0 src/diff/children.js
  8. +46 −2 test/browser/render.test.js
16 changes: 9 additions & 7 deletions compat/src/index.d.ts
Original file line number Diff line number Diff line change
@@ -115,14 +115,16 @@ declare namespace React {
) => preact.VNode<any>;
export function isValidElement(element: any): boolean;
export function isFragment(element: any): boolean;
export function isMemo(element: any): boolean;
export function findDOMNode(
component: preact.Component | Element
): Element | null;

export abstract class PureComponent<P = {}, S = {}, SS = any> extends preact.Component<
P,
S
> {
export abstract class PureComponent<
P = {},
S = {},
SS = any
> extends preact.Component<P, S> {
isPureReactComponent: boolean;
}

@@ -174,9 +176,9 @@ declare namespace React {

export type ComponentPropsWithRef<
C extends ComponentType<any> | keyof JSXInternal.IntrinsicElements
> = C extends (new(props: infer P) => Component<any, any>)
? PropsWithoutRef<P> & RefAttributes<InstanceType<C>>
: ComponentProps<C>;
> = C extends new (props: infer P) => Component<any, any>
? PropsWithoutRef<P> & RefAttributes<InstanceType<C>>
: ComponentProps<C>;

export function flushSync<R>(fn: () => R): R;
export function flushSync<A, R>(fn: (a: A) => R, a: A): R;
17 changes: 17 additions & 0 deletions compat/src/index.js
Original file line number Diff line number Diff line change
@@ -63,6 +63,21 @@ function isFragment(element) {
return isValidElement(element) && element.type === Fragment;
}

/**
* Check if the passed element is a Memo node.
* @param {*} element The element to check
* @returns {boolean}
*/
function isMemo(element) {
return (
!!element &&
!!element.displayName &&
(typeof element.displayName === 'string' ||
element.displayName instanceof String) &&
element.displayName.startsWith('Memo(')
);
}

/**
* Wrap `cloneElement` to abort if the passed element is not a valid element and apply
* all vnode normalizations.
@@ -215,6 +230,7 @@ export {
Fragment,
isValidElement,
isFragment,
isMemo,
findDOMNode,
Component,
PureComponent,
@@ -263,6 +279,7 @@ export default {
isValidElement,
isElement,
isFragment,
isMemo,
findDOMNode,
Component,
PureComponent,
37 changes: 37 additions & 0 deletions compat/test/browser/isMemo.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { createElement as preactCreateElement, Fragment } from 'preact';
import React, { createElement, isMemo, memo } from 'preact/compat';

describe('isMemo', () => {
it('should check return false for invalid arguments', () => {
expect(isMemo(null)).to.equal(false);
expect(isMemo(false)).to.equal(false);
expect(isMemo(true)).to.equal(false);
expect(isMemo('foo')).to.equal(false);
expect(isMemo(123)).to.equal(false);
expect(isMemo([])).to.equal(false);
expect(isMemo({})).to.equal(false);
});

it('should detect a preact memo', () => {
function Foo() {
return <h1>Hello World</h1>;
}
let App = memo(Foo);
expect(isMemo(App)).to.equal(true);
});

it('should not detect a normal element', () => {
function Foo() {
return <h1>Hello World</h1>;
}
expect(isMemo(Foo)).to.equal(false);
});

it('should detect a preact vnode as false', () => {
expect(isMemo(preactCreateElement(Fragment, {}))).to.equal(false);
});

it('should detect a compat vnode as false', () => {
expect(isMemo(React.createElement(Fragment, {}))).to.equal(false);
});
});
2 changes: 1 addition & 1 deletion devtools/src/devtools.js
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import { options, Fragment, Component } from 'preact';

export function initDevTools() {
if (typeof window != 'undefined' && window.__PREACT_DEVTOOLS__) {
window.__PREACT_DEVTOOLS__.attachPreact('10.19.7', options, {
window.__PREACT_DEVTOOLS__.attachPreact('10.20.0', options, {
Fragment,
Component
});
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "preact",
"amdName": "preact",
"version": "10.19.7",
"version": "10.20.0",
"private": false,
"description": "Fast 3kb React-compatible Virtual DOM library.",
"main": "dist/preact.js",
4 changes: 4 additions & 0 deletions src/diff/children.js
Original file line number Diff line number Diff line change
@@ -116,6 +116,9 @@ export function diffChildren(
childVNode._flags & INSERT_VNODE ||
oldVNode._children === childVNode._children
) {
if (!newDom && oldVNode._dom == oldDom) {
oldDom = getDomSibling(oldVNode);
}
oldDom = insert(childVNode, oldDom, parentDom);
} else if (
typeof childVNode.type == 'function' &&
@@ -241,6 +244,7 @@ function constructNewChildrenArray(newParentVNode, renderResult, oldChildren) {
if (oldVNode._dom == newParentVNode._nextDom) {
newParentVNode._nextDom = getDomSibling(oldVNode);
}

unmount(oldVNode, oldVNode, false);

// Explicitly nullify this position in oldChildren instead of just
48 changes: 46 additions & 2 deletions test/browser/render.test.js
Original file line number Diff line number Diff line change
@@ -1481,8 +1481,8 @@ describe('render()', () => {

expect(serializeHtml(scratch)).to.equal(
'<div><p>_B1</p><p>_B2</p><p>_B3</p><h2>_B4</h2><p>_B5</p><p>_B6</p><p>_B7</p><h2>_B8</h2><p>_B9</p><p>_B10</p><p>_B11</p><p>_B12</p><h2>_B13</h2></div>'
);
});
);
});

it('should not crash or repeatedly add the same child when replacing a matched vnode with null (mixed dom-types)', () => {
const B = () => <div>B</div>;
@@ -1537,4 +1537,48 @@ describe('render()', () => {
'<div><span>A</span><div>B</div><div>C</div></div>'
);
});

it('should shrink lists', () => {
function RenderedItem({ item }) {
if (item.renderAsNullInComponent) {
return null;
}

return <div>{item.id}</div>;
}

function App({ list }) {
return (
<div>
{list.map(item => (
<RenderedItem key={item.id} item={item} />
))}
</div>
);
}

const firstList = [
{ id: 'One' },
{ id: 'Two' },
{ id: 'Three' },
{ id: 'Four' }
];

const secondList = [
{ id: 'One' },
{ id: 'Four', renderAsNullInComponent: true },
{ id: 'Six' },
{ id: 'Seven' }
];

render(<App list={firstList} />, scratch);
expect(scratch.innerHTML).to.equal(
'<div><div>One</div><div>Two</div><div>Three</div><div>Four</div></div>'
);

render(<App list={secondList} />, scratch);
expect(scratch.innerHTML).to.equal(
'<div><div>One</div><div>Six</div><div>Seven</div></div>'
);
});
});