如何防止复合组件重新渲染?

时间:2019-09-20 19:52:49

标签: javascript reactjs typescript

我正在使用react上下文,目前它包含的所有3个项目:contactseditingContact,以及editContact

interface ContactsContextProps {
  contacts: Contact[];
  editingContact: Contact;
  editContact: (contact: Contact) => () => void // being lazy and this is from an onClick
}

const ContactsContext = React.createContext<Partial<ContactsContextProps>>({
  editContact: (contact: Contact) => () => {}
})

const ContactsProvider: React.FunctionComponent = props => {
  const [contacts, setContacts] = useState<Contact[]>();
  const [editingContact, setEditingContact] = useState<Contact>();

  React.useEffect(() => {
   // fetch contacts, and setContacts(contacts)
  }, [])

  const editContact = React.useCallback((contact: Contact) => {
    return function() {
      setEditingContact(contact);
    }
  })

  return (
    <ContactsContext.Provider
      value={{
        editingContact,
        editContact,
        contacts
      }}
    >
      {props.children}
    </ContactsContext.Provider>
  )
}

使用方法如下:

const ContactsList: React.FunctionComponent<{
  contacts: Contact[];
}> = React.memo(props => {
  return (
    <>
      {props.contacts.map(contact => (
        <Card key={contact.id} contact={contact} />
      ))}
    </>
  );
});

const Wrapper: React.FunctionComponent = () => {
  const contactsCtx = React.useContext(ContactsContext);

  return (
    <>
      <Box className={styles.main}>
        <Header />
        {contactsCtx.contacts && <ContactsList contacts={contactsCtx.contacts} />}
      </Box>
      {contactsCtx.editingContact && <EditContactModal />}
    </>
  );
};

<Card />现在只有一个编辑按钮,它调用contactsContext.editContact()。但是,每次调用时,所有卡都会重新渲染。我在每个卡中放置一个console.log('card'),它记录了card 10次(我现在有10个联系人)。

我在做什么错?

1 个答案:

答案 0 :(得分:1)

React Github issue中进行了讨论,基本上有3种可能的解决方案:

  • 选项1(首选):拆分不会一起更改的上下文
  • 选择2:将您的组件一分为二,在其中插入memo
  • 选项3:一个内部带有useMemo的组件

您应检查链接以获取有关示例。