Búsqueda de sitios web

javascript - ¿Cómo puedo evitar que un componente compuesto se vuelva a renderizar?


Estoy usando el contexto de React, y todo lo que contiene en este momento son 3 elementos: contacts y editingContact, y 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>
  )
}

Aquí está cómo se está utilizando:

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 />}
    </>
  );
};

El <Card /> solo tiene un botón de editar en este momento, que llama a contactsContext.editContact(). Sin embargo, cada vez que esto se llama, todas las Cards se vuelven a renderizar. Coloqué un console.log('card') en cada Card, y registra card 10 veces (ahora tengo 10 contactos).

¿Qué estoy haciendo mal?

Respuesta #1

Ha habido una discusión en un issue de Github de React, básicamente hay 3 soluciones posibles para esto:

  • Opción 1 (Preferida): Dividir contextos que no cambian juntos
  • Opción 2: Divide tu componente en dos, coloca memo en medio
  • Opción 3: Un componente con useMemo dentro

Deberías revisar el enlace para ver ejemplos sobre ello.