Dalam React, saya selalunya perlu menggunakan sesuatu seperti useCallback
untuk mengingati fungsi dalam senarai item (dicipta melalui gelung) untuk mengelakkan memaparkan semula semua komponen jika satu elemen berubah disebabkan pengecam rujukan yang tidak sepadan... Malangnya, ini amat sukar untuk tamat tempoh. Sebagai contoh, pertimbangkan kod berikut:
const MyComp = memo({elements} => { { elements.map((elt, i) => { <>{elt.text}<Button onClick={(e) => dispatch(removeElement({id: i}))}> <> }) } })
di mana Button
adalah komponen luaran yang disediakan oleh reka bentuk semut dll. Rujukan fungsi ini kemudiannya akan berbeza pada setiap pemaparan kerana ia adalah sebaris, sekali gus memaksa pemaparan semula.
Untuk mengelakkan masalah ini, saya boleh memikirkan penyelesaian lain: buat komponen baharu MyButton
,它接受两个属性 index={i}
和 onClick
而不是单个 onClick
,并将参数 index
附加到任何调用onClick
:
const MyButton = ({myOnClick, id, ...props}) => { const myOnClickUnwrap = useCallback(e => myOnClick(e, id), [myOnClick]); return <Button onClick={myOnClickUnwrap} ...props/> }; const MyComp = memo({elements} => { const myOnClick = useCallback((e, id) => dispatch(removeElement({id: id})), []); return { elements.map((elt, i) => { <>{elt.text}<Button id={i} onClick={myOnClick}> <> }) } )
Walaupun ini berfungsi, ia sangat tidak praktikal kerana beberapa sebab:
Button
semua elemen dalam perpustakaan luaran seperti <MyButton index1={index1} index2={index2} index3={index3 onClick={myFunction}>
,这意味着我需要完全通用地创建一个更复杂的版本 MyButton
来检查嵌套级别的数量。我无法使用 index={[index1,index2,index3]}
Gabungan ini adalah buruk: jika saya ingin menyarangkan elemen dalam berbilang senarai, ia akan menjadi lebih kotor kerana saya perlu menambah indeks baharu pada setiap peringkat senarai, seperti index
Setahu saya, tiada konvensyen penamaan untuk Adakah saya kehilangan penyelesaian yang lebih baik? Memandangkan senarai ada di mana-mana, saya tidak percaya tidak ada penyelesaian yang sesuai untuk ini, dan saya terkejut melihat betapa sedikit dokumentasi yang ada mengenai perkara ini.
Edit
Saya cuba ini:
// Define once: export const WrapperOnChange = memo(({onChange, index, Component, ...props}) => { const onChangeWrapped = useCallback(e => onChange(e, index), [onChange, index]); return <Component {...props} onChange={onChangeWrapped} /> }); export const WrapperOnClick = memo(({onClick, index, Component, ...props}) => { const onClickWrapped = useCallback(e => onClick(e, index), [onClick, index]); return <Component {...props} onClick={onClickWrapped} /> });dan gunakannya seperti ini:
onClick
,onChange
,...),如果我有它就无法直接工作多个属性(例如 onClick
和 onChange
const myactionIndexed = useCallback((e, i) => dispatch(removeSolverConstraint({id: i})), []); return <WrapperOnClick index={i} Component={Button} onClick={myactionIndexed} danger><CloseCircleOutlined /></WrapperOnClick>Tetapi ia masih tidak sempurna, khususnya saya memerlukan pembungkus untuk tahap bersarang yang berbeza, dan setiap kali saya menyasarkan harta baharu, saya perlu mencipta versi baharu (), saya tidak pernah melihatnya sebelum ini, jadi saya Mahukan penyelesaian yang lebih baik .
Edit
Saya mencuba pelbagai idea, termasuk menggunakan fast-memoize, tetapi saya masih tidak memahami semua keputusan: kadangkala, fast-memoize berfungsi, kadangkala ia gagal... dan saya tidak tahu sama ada fast-memoize ialah penyelesaian yang disyorkan: Nampaknya pelik menggunakan alat pihak ketiga untuk kes penggunaan biasa seperti itu. Lihat ujian saya di sini https://codesandbox.io/embed/magical-dawn-67mgxp?fontsize=14&hidenavigation=1&theme=dark🎜
Uji di sini https://codesandbox.io /s/sharp-wind-rd48q4?file=/src/App.js
Amaran: Saya bukan pakar React (oleh itu soalan saya!), jadi sila komen di bawah dan/atau tambahkan +1 jika anda fikir penyelesaian ini adalah cara kanonik untuk melakukannya dalam React (atau -1 jika tidak ^^ ). Saya juga ingin tahu mengapa beberapa penyelesaian lain gagal (cth. berdasarkan proksi-memoize (yang sebenarnya mengambil masa 10x lebih lama daripada tiada caching, dan tidak cache sama sekali) atau fast-memoize (yang tidak selalu cache, bergantung pada cara Saya menggunakannya )), jadi jika anda tahu saya berminat untuk mengetahuinya)
Memandangkan saya kurang berminat dalam masalah ini, saya cuba menanda aras sekumpulan penyelesaian (14!) terhadap pelbagai pilihan (tiada memori, menggunakan perpustakaan luaran (memori cepat vs. memori proksi), menggunakan pembungkus), menggunakan Komponen luaran dsb. .
Cara terbaik nampaknya ialah mencipta komponen baharu mengandungi keseluruhan elemen senarai, bukan hanya butang terakhir. Ini membolehkan kod yang cukup bersih (walaupun saya perlu mencipta dua komponen untuk senarai dan item, sekurang-kurangnya ia masuk akal dari segi semantik), mengelakkan perpustakaan luaran, dan nampaknya lebih cekap daripada semua yang saya cuba (sekurang-kurangnya pada pendapat saya (contohnya):
Saya masih tidak begitu menyukai penyelesaian ini kerana saya perlu memajukan banyak kandungan daripada komponen induk kepada komponen anak, tetapi ini nampaknya penyelesaian terbaik yang saya boleh dapatkan...
Anda boleh melihat senarai percubaan saya di sini, saya menggunakan kod di bawah. Berikut ialah pandangan dari profiler (secara teknikalnya perbezaan masa antara semua versi tidak begitu besar (kecuali versi 7 yang menggunakan proxy-memoize, saya mengeluarkannya kerana ia lebih panjang, mungkin 10x, dan sedang dibuat Carta lebih sukar dibaca) , tetapi saya menjangkakan perbezaan ini lebih besar pada senarai yang lebih panjang, di mana item lebih kompleks untuk dilukis (di sini saya hanya mempunyai satu teks dan satu butang). Ambil perhatian bahawa semua versi tidak betul-betul sama (sesetengahnya menggunakan
,一些
, beberapa senarai biasa, beberapa senarai rekaan Ant...), jadi perbandingan masa hanya bermakna antara versi yang menjalankan operasi yang sama. Bagaimanapun, kebimbangan utama saya adalah untuk melihat apa yang dicache dan apa yang tidak dicache, yang jelas kelihatan dalam profiler (blok kelabu muda dicache):
Satu lagi fakta menarik ialah anda mungkin ingin menanda aras sebelum menghafal, kerana peningkatan mungkin tidak ketara, sekurang-kurangnya untuk komponen mudah (saiz 5 di sini, hanya satu teks dan satu butang).