Celestriel
Celestriel

Reputation: 377

React.js - this.props.children an object when spreading the result of a .map from the parent

I am having some strange behaviour where this.props.children is converting to an object when I spread the result of a .map() from the parent.

example:

const items = [
  { id: 1, name: "Name1" },
  { id: 2, name: "Name2" }
].map((item) => {
  return (
    <DropdownMenu_listItem key={item.id} item={item} />
  );
});

render() {
  return (
    <DropdownMenu
      label={'Some label'}
      onChange={() => {}}
    >
      {...items}
    </DropdownMenu>
  );
}

// DropdownMenu.js

render() {
  console.log(this.props.children); // {0: {…}, 1: {…}}

  return (
    // ...
  );
}

The weird part is that when I omit the .map() and pass the elements directly, they appear in this.props.children as an array like expected:

render() {
  return (
    <DropdownMenu
      label={'Some label'}
      onChange={() => {}}
    >
      <DropdownMenu_listItem item={{...}} />
      <DropdownMenu_listItem item={{...}} />
    </DropdownMenu>
  );
}

// DropdownMenu.js

render() {
  console.log(this.props.children); // [{…}, {…}]

  return (
    // ...
  );
}

Any insight into why this is happening would be greatly appreciated.

Upvotes: 12

Views: 26407

Answers (3)

Bambier
Bambier

Reputation: 846

In my case passing as attr will worked

before

function Foo(props) {
    return <Bar> {...props} </Bar>
}

after

function Foo(props) {
    return <Bar {...props}> </Bar>
}

Upvotes: 4

RIYAJ KHAN
RIYAJ KHAN

Reputation: 15292

{...items} is passed as childrens in DropdownMenu.js.

Its available as a this.props.children

this.props.children can be array or object depend on how you rendering the children elements.

in your case

<DropdownMenu
      label={'Some label'}
      onChange={() => {}}
    >
      {...items}
</DropdownMenu>

items is an array. As we know

array is also type of object in javascript

with key equal to element's index and value is element itself

{...items} : this will passed as a object with key as a element index and value equal to array element.

To fix your problem, you should passed it without using spread operator.

{items} : this will passed as an array.

<DropdownMenu
      label={'Some label'}
      onChange={() => {}}
    >
      {items}
</DropdownMenu>

Upvotes: 7

Shubham Khatri
Shubham Khatri

Reputation: 281736

Its not because of map that you get children as object, but because you use spread operator for the items in

<DropdownMenu
          label={'Some label'}
          onChange={() => {}}
        >
          {...items} {/*spread operator here */}
</DropdownMenu>

Now that after map items is an array using {...items } makes it an object since you wrap your result of spread operator with {}, If you write {items}, that will be fine

 <DropdownMenu
      label={'Some label'}
      onChange={() => {}}
    >
      {items}
 </DropdownMenu>

Upvotes: 7

Related Questions