2

In a React application, I'm passing in this array of objects to a component:

const flashcards = [
    {
        "back": "bbb1",
        "front": "fff1",
        "id": 21
    },
    {
        "back": "bbb2",
        "front": "fff2",
        "id": 22
    },
    {
        "back": "bbb3",
        "front": "fff3",
        "id": 20
    }
];

In the component, when I map through the array, why do I need to have a spread operator in order to send individual items from the array to the next lower component (Flashcard), e.g. like this:

render() {
    return (
        <div className="app">
            <div>
                {this.props.flashcards.map(flashcard =>
                    <Flashcard {...flashcard} key={flashcard.id} />
                    )}
            </div>
        </div>
    );
}

This seems superfluous, since when I use map in plain JavaScript on the same array, I do not need the spread operator, e.g.:

flashcards.map(flashcard => console.log(flashcard.front));
Edward Tanguay
  • 189,012
  • 314
  • 712
  • 1,047
  • 1
    `flashcards.map(flashcard => console.log(flashcard.front));` is not at all the same operation as the above one. First of all, it's funamentally wrong: `.map()` is [for transforming the array's contents to a new array](https://stackoverflow.com/questions/56903693/is-performing-a-mapping-operation-without-using-returned-value-an-antipattern), so a using a simple log is not what `.map` is about. It's also the crux of the issue - a proper mapping in JS would be `flashcards.map(flashcard => {...flashcard, [key] = flashcard.id})` which is now remarkably similar to the first example. – VLAZ Aug 17 '20 at 10:10
  • 1
    Thanks @VLAZ, that insight helped me understand this. I got your example to work which makes sense, but you have to surround the brackets with parentheses to indicate that the brackets are meant to create an object and are not function brackets: `const frontFlashcards = flashcards.map(flashcard => ({...flashcard, key: flashcard.id}));` – Edward Tanguay Aug 17 '20 at 10:46
  • Yes, sorry - my bad there. You do indeed need `()` around it. It's a syntax quirk otherwise `{}` is interpreted as the body, not an object literal. – VLAZ Aug 17 '20 at 11:37

3 Answers3

5

{...flashcard} - This basically spreads the properties in flashcard object on the props object that Flashcard component will receive.

This is not necessary if you don't want to pass all the properties of flashcard object as props to Flashcard component.

Think of this

<Flashcard {...flashcard} key={flashcard.id} />

as a shorter way of writing this:

<Flashcard
   key={flashcard.id}
   back={flashcard.back}
   front={flashcard.front}
   id={flashcard.id}
/>
Yousaf
  • 27,861
  • 6
  • 44
  • 69
  • Ok, I think my confusion here was that I'm coming from Vue.js to React and I just assumed one could pass the whole flashcard object as I am accustomed to doing in Vue.js, e.g. `` or `@click="flipFlashcard(flashcard)"`. Is this not possible in React/JSX? – Edward Tanguay Aug 17 '20 at 10:50
  • You can pass the whole `flashcard` object ---> ``. `props` object will now have a property named `flashcard` whose value will be this `flashcard` object. Difference between `{...flashcard}` and `flashcard={flashcard}` is that former will add each property of `flashcard` object on the `props` object whereas `flashcard={flashcard}` will add a `flashcard` property on the `props` object. – Yousaf Aug 17 '20 at 10:53
3

Because props were meant to flow in single direction, which is from parent to child. And when you have a prop which is a reference value such as array or object. Any write operation to it will change the value in reference memory which will modify the prop from child component. Hence destructing it creates a new memory reference and saves it from getting modified


Satyam Pathak
  • 6,612
  • 3
  • 25
  • 52
  • That occurred to me, but my Flashcard.js component is receiving a flashcard object, e.g. `const Flashcard = (flashcard) => (` and if I am actually sending down numerous parameters, why don't I have to receive each one individually as e.g. `const Flashcard = (front, back, id) => (`? – Edward Tanguay Aug 17 '20 at 10:57
  • 1
    @EdwardTanguay If you are passing down props to `Flashcard` component as ``, then you have to destructure them from the `props` object ---> `const Flashcard = ({ front, back, id }) => (` and if you pass whole `flashcard` object as `` then you need to destructure `flashcard` property from the `props` object ---> `const Flashcard = ({ flashcard }) => (`. Component doesn't receives the props directly, instead each prop is passed to the component as a property of `props` object. – Yousaf Aug 17 '20 at 11:02
0

Because it is syntactical sugar. Otherwise you had to write out the properties like in your example e.g.

 {this.props.flashcards.map(flashcard =>
      <Flashcard back={flashcard.back} front={flashcard.front} key={flashcard.id} />
  )}
Murat Karagöz
  • 35,401
  • 16
  • 78
  • 107