I'm quite new to Hooks and I am trying to build a small address book.
So I have two components:
I want cards to be removed when the X is clicked. I managed to toggle the deleted prop of my contact, but I can't figure out how to force re-render the ContactsList
then
import React, { useState } from 'react'
import ContactsList from './components/contacts-list/contacts-list.component'
import './App.scss'
function App() {
const [contacts] = useState([
{
key: 0,
name: 'Lennon',
firstname: 'John',
notes: 'smart guy',
deleted: false
},
{
key: 1,
name: 'Starr',
firstname: 'Ringo',
notes: 'funny guy',
deleted: false
}
])
return (
<div className='App'>
<ContactsList contacts={contacts} />
</div>
)
}
export default App
import React, { useState, useEffect } from 'react'
import ContactCard from '../contact-card/contact-card.component'
import './contacts-list.styles.scss'
function ContactsList(props) {
const [contacts, setContacts] = useState(props.contacts)
return (
<div className='contacts-list'>
<span className='title'>Contacts</span>
{contacts
.filter(contact => contact.deleted === false)
.map(contact => (
<ContactCard
name={contact.name}
firstname={contact.firstname}
notes={contact.notes}
deleted={contact.deleted}
/>
))}
<hr />
</div>
)
}
export default ContactsList
import React, { useState } from 'react'
import './contact-card.styles.scss'
function ContactCard(props) {
const [contact, setContact] = useState([
{
name: props.name,
firstname: props.firstname,
notes: props.notes,
deleted: false
}
])
function deleteContact() {
const currentContact = [...contact]
currentContact[0].deleted = true
setContact(currentContact)
}
return (
<div className='contact-card'>
<span className='contact-name'>{props.name}</span>
<span className='delete-contact' onClick={deleteContact}>
✕
</span>
<br />
<span className='contact-firstname'>{props.firstname}</span>
<hr className='separator' />
<span className='contact-notes'>{props.notes}</span>
</div>
)
}
export default ContactCard
Really a few options here, the simplest is probably just to pass in an 'onContactDeleted' prop and callback to the parents to let them know to update the state. This method isn't always the cleanest, especially with highly nested components but I would recommend it as a start is as it really is the most vanilla way that will help you understand how prop and state changes work. Note that I kept your soft delete method but you could also just remove it from the list.
Card
import React, { useState } from 'react'
import './contact-card.styles.scss'
function ContactCard(props) {
function deleteContact(key) {
props.onContactDeleted(key)
}
return (
<div className='contact-card'>
<span className='contact-name'>{props.name}</span>
<span className='delete-contact' onClick={() => deleteContact(props.contactKey)}>
✕
</span>
<br />
<span className='contact-firstname'>{props.firstname}</span>
<hr className='separator' />
<span className='contact-notes'>{props.notes}</span>
</div>
)
}
export default ContactCard
List
import React, { useState, useEffect } from 'react'
import ContactCard from '../contact-card/contact-card.component'
import './contacts-list.styles.scss'
function ContactsList(props) {
const [contacts, setContacts] = useState(props.contacts)
return (
<div className='contacts-list'>
<span className='title'>Contacts</span>
{contacts
.filter(contact => contact.deleted === false)
.map(contact => (
<ContactCard
contactKey={contact.key}
name={contact.name}
firstname={contact.firstname}
notes={contact.notes}
deleted={contact.deleted}
onContactDeleted={props.onContactDeleted}
/>
))}
<hr />
</div>
)
}
export default ContactsList
App
import ContactsList from './components/contacts-list/contacts-list.component'
import './App.scss'
function App() {
const [contacts, setContacts] = useState([
{
key: 0,
name: 'Lennon',
firstname: 'John',
notes: 'smart guy',
deleted: false
},
{
key: 1,
name: 'Starr',
firstname: 'Ringo',
notes: 'funny guy',
deleted: false
}
])
return (
<div className='App'>
<ContactsList contacts={contacts}
onContactDeleted={
(key_to_delete) => {
//note this might not be correct, use it as pseudocode
var copy = [...contacts]
var contact = copy.find(x => x.key == key_to_delete)
if(contact)
{
contact.deleted = true;
setContacts(copy)
}
}
}/>
</div>
)
}
export default App
Once you have that you could use something like redux or the useContext
hook to share the state and "cut out the middle man"
Here is an example of the useContext
hook that I quickly found online, not sure how good it is