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
memoen medio - Opción 3: Un componente con
useMemodentro
Deberías revisar el enlace para ver ejemplos sobre ello.