Skip to content
This repository was archived by the owner on Dec 16, 2021. It is now read-only.

fix: children.map when new child return null #461

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,26 @@ function unmountComponentAtNode(container) {
const ARR = [];

// This API is completely unnecessary for Preact, so it's basically passthrough.

let Children = {
map(children, fn, ctx) {
if (children == null) return null;
children = Children.toArray(children);
if (ctx && ctx!==children) fn = fn.bind(ctx);
return children.map(fn);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not return children.map(fn).filter(item => item !== null);

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when the children has true or false, React will ignore them, see the demo

// demo
let instance = (
    <div>
      {'123'}
      {true}
      {false}
    </div>
);
class Hello extends React.Component {
  render() {
    console.info(instance.props.children); //  ["123", true, false]
    const ChildrenMap = React.Children.map(instance.props.children, item => item);
    console.info(ChildrenMap); // ["123"]
    return <div>
     {ChildrenMap}
    </div>
  }
}
ReactDOM.render(<Hello/>, document.getElementById('test'));    

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, i see we need to skip boolean and null, undefined

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't it only skip rendering?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, react does much more in React.Children.Map, but I think skip rendering is the the main difference between react-compat and react. The main purpose of this pull request is to improve compatibility.

const newChildren = [];

children.forEach((old, index) => {
if (old === void 0 || old === false || old === true) {
old = null;
}
const newChild = fn(old, index);
if (newChild == null) { // when the return value is null, ignore
return;
}
newChildren.push(newChild);
});

return newChildren;
},
forEach(children, fn, ctx) {
if (children == null) return null;
Expand Down Expand Up @@ -592,7 +606,7 @@ PureComponent.prototype.shouldComponentUpdate = function(props, state) {
};

function unstable_batchedUpdates(callback) {
callback();
callback();
}

export {
Expand Down
32 changes: 32 additions & 0 deletions test/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -543,4 +543,36 @@ describe('components', () => {
expect(spy).not.to.have.been.called;
});
});

describe('ReactChildren', () => {
it("should ignore when child return null", () => {
let zero = <div key="keyZero" />;
let one = null;
let two = <div key="keyTwo" />;
let three = null;
let four = <div key="keyFour" />;

let mapped = [
<div key="giraffe" />, // Key should be joined to obj key
null, // Key should be added even if we don't supply it!
<div />, // Key should be added even if not supplied!
<span />, // Map from null to something.
<div key="keyFour" />
];
let instance = (
<div>
{zero}
{one}
{two}
{three}
{four}
</div>
);
const mappedChildren = React.Children.map(instance.props.children, (kid, index) => mapped[index]);
expect(mappedChildren[0]).to.equal(<div key="giraffe" />);
expect(mappedChildren[1]).to.equal(<div/>);
expect(mappedChildren[2]).to.equal(<span/>);
expect(mappedChildren[3]).to.equal(<div key="keyFour" />);
});
});
});