使用钩子从父组件进行状态管理
State management from parent component using hooks
我对 Hooks 很陌生,我正在尝试构建一个小型地址簿。
所以我有两个组成部分:
- 一个 ContactCard 组件
- 联系人列表组件
我希望在单击 X 时删除卡片。我设法切换了我的联系人的 deleted 道具,但我不知道如何强制重新呈现 ContactsList
然后
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
从您的 App
开始,我建议您将您的联系人对象移动到常量,因为此级别不需要 useState
。
// constants.js
export const contacts = [
{
key: 0,
name: 'Lennon',
firstname: 'John',
notes: 'smart guy'
},
{
key: 1,
name: 'Starr',
firstname: 'Ringo',
notes: 'funny guy'
}
]
};
// App.js
import React from 'react';
import { contacts } from './constants';
import ContactsList from './components/contacts-list/contacts-list.component'
import './App.scss'
function App() {
return (
<div className='App'>
<ContactsList contacts={contacts} />
</div>
)
}
export default App
继续 ContactList
组件,因为它是呈现每个联系人的组件,所以我将在此处构建我的状态。这就是为什么,我会知道我是否需要事先提供联系方式。
import React, { useState } from 'react'
import ContactCard from '../contact-card/contact-card.component'
import './contacts-list.styles.scss'
function ContactsList(props) {
const [contacts, setContacts] = useState(props.contacts);
const handleDeletion = id => {
setContacts(contacts.filter(contact => contact.id !== id));
}
return (
<div className='contacts-list'>
<span className='title'>Contacts</span>
{contacts.length ?
contacts.map(contact =>
<ContactCard
id={contact.id}
name={contact.name}
firstname={contact.firstname}
notes={contact.notes}
handleDeletion={handleDeletion}
/>
) : null}
<hr />
</div>
)
}
export default ContactsList
请注意,我正在将处理删除的函数传递到我的 ContactCard,同时我仍在决定是否应该显示我的联系人。
import React from 'react'
import './contact-card.styles.scss'
function ContactCard(props) {
return (
<div className='contact-card'>
<span className='contact-name'>{props.name}</span>
<span className='delete-contact' onClick={() => props.handleDeletion(props.id)}>
✕
</span>
<br />
<span className='contact-firstname'>{props.firstname}</span>
<hr className='separator' />
<span className='contact-notes'>{props.notes}</span>
</div>
)
}
export default ContactCard
我还没有尝试过代码,但我认为你应该沿着这条路前进。
这里确实有几个选项,最简单的可能只是传递一个 'onContactDeleted' 属性并回调到 parents 让他们知道更新状态。这种方法并不总是最干净的,尤其是对于高度嵌套的组件,但我会推荐它作为开始,因为它确实是最原始的方法,可以帮助您了解 prop 和状态更改的工作原理。请注意,我保留了您的软删除方法,但您也可以将其从列表中删除。
卡片
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
列表
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
应用程序
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
一旦你有了它,你就可以使用 redux 或 useContext
钩子来共享状态和 "cut out the middle man"
下面是网上很快找到的useContext
钩子的例子,不知道好不好用
我对 Hooks 很陌生,我正在尝试构建一个小型地址簿。
所以我有两个组成部分:
- 一个 ContactCard 组件
- 联系人列表组件
我希望在单击 X 时删除卡片。我设法切换了我的联系人的 deleted 道具,但我不知道如何强制重新呈现 ContactsList
然后
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
从您的 App
开始,我建议您将您的联系人对象移动到常量,因为此级别不需要 useState
。
// constants.js
export const contacts = [
{
key: 0,
name: 'Lennon',
firstname: 'John',
notes: 'smart guy'
},
{
key: 1,
name: 'Starr',
firstname: 'Ringo',
notes: 'funny guy'
}
]
};
// App.js
import React from 'react';
import { contacts } from './constants';
import ContactsList from './components/contacts-list/contacts-list.component'
import './App.scss'
function App() {
return (
<div className='App'>
<ContactsList contacts={contacts} />
</div>
)
}
export default App
继续 ContactList
组件,因为它是呈现每个联系人的组件,所以我将在此处构建我的状态。这就是为什么,我会知道我是否需要事先提供联系方式。
import React, { useState } from 'react'
import ContactCard from '../contact-card/contact-card.component'
import './contacts-list.styles.scss'
function ContactsList(props) {
const [contacts, setContacts] = useState(props.contacts);
const handleDeletion = id => {
setContacts(contacts.filter(contact => contact.id !== id));
}
return (
<div className='contacts-list'>
<span className='title'>Contacts</span>
{contacts.length ?
contacts.map(contact =>
<ContactCard
id={contact.id}
name={contact.name}
firstname={contact.firstname}
notes={contact.notes}
handleDeletion={handleDeletion}
/>
) : null}
<hr />
</div>
)
}
export default ContactsList
请注意,我正在将处理删除的函数传递到我的 ContactCard,同时我仍在决定是否应该显示我的联系人。
import React from 'react'
import './contact-card.styles.scss'
function ContactCard(props) {
return (
<div className='contact-card'>
<span className='contact-name'>{props.name}</span>
<span className='delete-contact' onClick={() => props.handleDeletion(props.id)}>
✕
</span>
<br />
<span className='contact-firstname'>{props.firstname}</span>
<hr className='separator' />
<span className='contact-notes'>{props.notes}</span>
</div>
)
}
export default ContactCard
我还没有尝试过代码,但我认为你应该沿着这条路前进。
这里确实有几个选项,最简单的可能只是传递一个 'onContactDeleted' 属性并回调到 parents 让他们知道更新状态。这种方法并不总是最干净的,尤其是对于高度嵌套的组件,但我会推荐它作为开始,因为它确实是最原始的方法,可以帮助您了解 prop 和状态更改的工作原理。请注意,我保留了您的软删除方法,但您也可以将其从列表中删除。
卡片
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
列表
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
应用程序
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
一旦你有了它,你就可以使用 redux 或 useContext
钩子来共享状态和 "cut out the middle man"
下面是网上很快找到的useContext
钩子的例子,不知道好不好用