javascript - איך אני יכול למנוע מרכיב מורכב לעבור רינדור מחדש?


אני משתמש בקונטקסט של React, וכל מה שהוא מכיל כרגע הם 3 פריטים: contacts ו-editingContact, ו-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(). עם זאת, כל פעם שהפונקציה הזו מופעלת, כל ה-Cards מתרנדרים מחדש. שמתי console.log('card') בכל Card, והוא מדפיס card 10 פעמים (יש לי 10 אנשי קשר כרגע).

מה אני עושה לא נכון?

תשובה #1

התנהלה דיון בנושא ב-Github של React, בעיקר יש שלוש אפשרויות פתרון לכך:

  • אפשרות 1 (מומלצת): לפצל הקשרים שלא משתנים יחד
  • אפשרות 2: חלקו את הקומפוננטה שלכם לשניים, שימו memo ביניהם
  • אפשרות 3: רכיב אחד עם useMemo בפנים

כדאי לבדוק את הקישור לדוגמאות על זה.