I'm having trouble understanding a very weird bug while doing Part 2 on Full Stack Open. In few words: passing an object to the component turns the object into a nested object. Namely:
entries.map(entry => { console.log(entry); return <PhonebookEntry props={entry} />})
on App.js
and
function PhonebookEntry(props) {
console.log(props)
//rest of code
}
on index.js
don't work as expected.
When ran, the browser's console displays the following:
Object { name: "Derp", surname: "Derpington", phone: "012345", address: "2012 Street" }
App.js:33
Object { props: {…} }
props: Object { name: "Derp", surname: "Derpington", phone: "012345", … }
<prototype>: Object { … }
PhonebookEntry.js:2
Here's App.js
:
import { useState } from 'react'
import PhonebookEntry from './PhonebookEntry.js'
export default function App() {
function handleAddEntry(e) {
e.preventDefault()
setEntries(entries.concat({
name: newName,
surname: newSurname,
phone: newPhone,
address: newAddress
}))
}
const [entries, setEntries] = useState([
{
name: "Derp",
surname: "Derpington",
phone: "012345",
address: "2012 Street"
}
])
const [newName, setNewName] = useState('')
const [newSurname, setNewSurname] = useState('')
const [newPhone, setNewPhone] = useState('')
const [newAddress, setNewAddress] = useState('')
return (
<div>
<h1>Phonebook</h1>
<ul>
{entries.map(entry => { console.log(entry); return <PhonebookEntry props={entry} />})}
</ul>
<form onSubmit={handleAddEntry}>
Name: <input value={newName} onChange={(e) => setNewName(e.target.value) }/><br></br>
Surname: <input value={newSurname} onChange={(e) => setNewSurname(e.target.value)}/><br></br>
Phone: <input value={newPhone} onChange={(e) => setNewPhone(e.target.value)}/><br></br>
Address: <input value={newAddress} onChange={(e) => setNewAddress(e.target.value)}/><br></br>
<button type="submit">Add</button>
</form>
</div>
)
}
and here's PhonebookEntry.js
:
function PhonebookEntry(props) {
console.log(props)
return (
<li>
<div>
Name: {`${props.surname}, ${props.name}`}
</div>
<div>
Phone: {props.phone}
</div>
<div>
Address: {props.address}
</div>
</li>
)
}
export default PhonebookEntry
It’s not a bug, it’s a feature.
You can think of this:
<Component foo={bar} />
As this:
Component({ foo: bar })
Now, it’s a bit more complicated than just that, but really that’s what props in JSX represent.
So, just like how we have spread parameters/arguments, we also have spread props:
<PhonebookEntry {...entry} />
This is the same thing as (roughly):
PhonebookEntry({ ...entry })
https://reactjs.org/docs/jsx-in-depth.html#spread-attributes
Back to your original example,
<PhonebookEntry props={entry} />
Would just be
PhonebookEntry({ props: entry })
Which is why it’s nested.