使用挂钩从父组件进行状态管理

时间:2020-01-08 17:14:04

标签: javascript reactjs react-hooks react-state-management

我对Hooks来说还很陌生,我正在尝试制作一本小型通讯录。

所以我有两个组成部分:

  • ContactCard组件
  • ContactsList组件

我希望在单击 X 时删除卡。我设法切换了联系人的已删除道具,但是我不知道如何强制重新渲染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}>
        &#10005;
      </span>
      <br />
      <span className='contact-firstname'>{props.firstname}</span>
      <hr className='separator' />
      <span className='contact-notes'>{props.notes}</span>
    </div>
  )
}

export default ContactCard

2 个答案:

答案 0 :(得分:1)

这里确实有一些选择,最简单的方法可能只是传递“ onContactDeleted”属性并回调给父母,让他们知道更新状态。这种方法并非总是最干净的,尤其是对于高度嵌套的组件,但我建议它作为一个开始,因为它实际上是最有用的方法,可以帮助您了解prop和state更改的工作方式。请注意,我保留了您的软删除方法,但您也可以将其从列表中删除。

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)}>
        &#10005;
      </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钩之类的东西来共享状态并“裁剪中间人”

下面是我很快在网上发现的useContext钩子的一个示例,不确定它有多好

https://www.codementor.io/@sambhavgore/an-example-use-context-and-hooks-to-share-state-between-different-components-sgop6lnrd

答案 1 :(得分:0)

从您的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)}>
        &#10005;
      </span>
      <br />
      <span className='contact-firstname'>{props.firstname}</span>
      <hr className='separator' />
      <span className='contact-notes'>{props.notes}</span>
    </div>
  )
}

export default ContactCard

我还没有尝试过代码,但是我认为您应该沿着这条路前进。