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

3

12

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.

Bobbyebobbysocks answered 22/3, 2018 at 6:23 Comment(2)
Is there a reason behind this decision?Bobbyebobbysocks
check this answer, it will help. #40348671Pileus
B
7

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>
Bemock answered 22/3, 2018 at 6:34 Comment(2)
But OP mentioned that if he removes the map functionality then he is getting the array. As per your answer both the cases he should get object. is that correct?Pileus
@SureshPonnukalai In the second case he is manually adding <DropdownMenu_listItem item={{...}} /> <DropdownMenu_listItem item={{...}} /> as children and not using spread operatorBemock
U
7

{...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>
Unwholesome answered 22/3, 2018 at 6:36 Comment(1)
I was previously using { ...children } which didn't work so, I used { this.props.children } and it worked like a charm!Lucinalucinda
S
4

In my case passing as attr will worked

before

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

after

function Foo(props) {
    return <Bar {...props}> </Bar>
}
Sideshow answered 8/7, 2022 at 12:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.