Дзевяць распашчытых шаблонаў, якія спрычыняюць непатрэбнае перыскалявання компонентаў у React.
Паспрацавае над дзевяцьма повсякденнымі шаблонамі стану та ефектаў у React, які таямніча павяршчваюць масштаб перыскалявання, і паказвае, як рэструктураваць компоненты, каб апдейты заставаліся локальнымі.
Крыніцы: 9 React Habits That Quietly Cause Unnecessary Re-Renders
React зазвычай працюе быстро сама по сабе. Проблемы выявляюцься тады, калі адна мала змянэнне вымушвае значна большую частку дрэва компонента перацягнуць свою роботу, чым на самай працэ ўзмаўляе такая змянэнне.
Дзьвігу, здавалася, што чрэзмернае перерысаванне ўважалася чымось, што сам React павінен быў вылечыць. Калі компонент апдэйтаваўся больш, чым трэба, першым падказкам было абгорнуць яго ў memo, альбо скорыстацца useMemo і useCallback. Якщо інтерфейс усё раве заставаўся повольным, тады той жа падход застаўся і для наступных шароў компонентаў, у надзеі, што React зрэштыце стабілізуецца.
Такі способы патчавання іноды заставлялі графікі працэсу аналізу выглядаць краща, але рэдкасцю робілі структуру базовых компонентаў яшчэ болей зрозумелай. Статусы застаўаліся на вышэйшых роўнях дрэва, чым было трэба; значэнні контексту застаўаліся зборкаваныя разам, вырахоўваныя данні застаўаліся дуплікаванымі, рэферэнсы застаўаліся нестабільнымі, а эфекты заставаліся запускам дадатковых апдэйтаў як толькі ўжо запускаліся. Мемаізацыя фактычна выкорыстоўвалася для таго, каб захаваць інтерфейс ад потоку даных, які быў шырэй, чым трэба.
Сам практычны перысвечванне не ёсць багам. React прадуманы так, каб знову вызываць функціі вашых компонентаў кожны раз, калі їхні вхідныя данні моглі зменіцца, і багато компонентаў є настолькі дешавыя, што блакуванне кожнага безнэпасныя перысвечвання прыносіць больш сложнасці, чым заўважвае.
Праўяй запыт не ў тым, чы рэндаруўся компонент знову. Ён у тым, чаму быў запусканы гэты рэндар, і якая праца адбывалася пасля таго, как React яго вызваў.
Большая частка непатрэбных перыядражэнняў выклікаецца прывычкамі, якія здаюцца безнэшкоднымі, калі компанента мала. Їхнія наследкі стаюць виднымі толькі пазней, калі компанента расте, яе дзеця стаюць масавейшымі, але ці значэнняя, якія быстра змінююцца, пачынаюць узневажальваць вялікі частак сторанкі.
1. Зберагчы часта змінююцыся стан у высокай частцы дрэва
Перанесенне стану да спакойнага праўедзіча ёсць адным з першых патэранаў, якія вывучаюць разработчыкаў React. Калі две компаненты выкорыстоўваюць адно і тое ж значэнне, перадача ўлады яго найбліжэйшаму спакойнаму праўедзічу дапамагае падтрымваць сінхроннасць і узбегаць дуплікацыі аднародных джэраў правды.
Гэта стае проблемай, калі кожны элемент локальнага стану взаінаўпрацы падаецца да компаненту на рэвэлі сторанкі проста таму, што гэты компанент мае доступ да всьога.
Поле пошуку заставляе свае значэнне застацца на панелі керування. Флаг адкрытаг/закрытаг выпадаючага спісу знаходзится пры данных таблыцы. Стан наведэння стежыцца за дапамою сеткі картак. Поле формы в модалным вікні керуецца экранам, який яго адкрыў. Кожны натык клавішы чыста прыводзіць да таго, што верхній власнік змушаны перзначыць відображэнне.
Паколькі компонент сторанцы ў кожны раз вяртае своіх дзецей у чыстам стане, адкорэктаванне тексту пошуку можа спрычыніць паўтарную обработку графікаў, таблыц, навігацыі і дыялоговых вікон, нават якфале ў іх рэальных данных не было ніякіх змян.
Гэта таксама не ўмоўліванне для таго, каб кожны элемент дзяржавнай структуры ховаць якомога глыбэй. Дзяржавна структура павінна знаходзіцца на самай маленькай грані, якая ўсё ж такі трэбае координаваць адповідныя складовы. Фільтр, ад якога залежна URL, таблыця і кнопка экспорту, верагатывае, павінен знаходзіцца вышэй за гэтыя регіоны. Чы хто-небудзь зараз відкрывае падказку, зазвычай не трэба, каб яя таксама знаходзілася там.
Гэта разыяўленне мае важнае значэння для значэнняў, якія быстра абновляюцца. Набіранне тексту, ператаскванне элементаў, следзенне за курсорам, прыбліжны статус анімацыі і рэальныя поля формы можу ствараць многія абноўлення за секунду. Якшчы разместіць адны з гэтых элементаў вышэй за дорогі паддрэс, то чыста локальная взаімодзея ператвараецца на работу для цэлага сторанніка.
Прыткасць стану да компанентаў, якія яго фактычна выкарыстоўваюць, зазвычай дапамагае болей прымусова паспрабаваць падняць карыстоўнасць, чым выкорыстанне мемаізацыі для всей старонкі, адтак як у React няма родніка, які мог бы зноў паставіць стан у недзейнае становішча, калі гэты роднік больш не володзі цым станам.
2. Выкорыстанне аднаго контэксту для некаляжных значэнняў
Контэкст існуе для рашэння адзінаго конкрэтнага проблемы: дазволеныя падкомпанентам чытаць спакульнаваныя значэння без прымусу кожнага компанента між імі перадаваць пропсы, якія ён ніколі не выкарыстоўвае.
Проблэмы пачынаюцца, калі адзін прадастар ператвараецца на ўніверсальны контейнер для всьога, што вважаецца "глобальным"
Часта бачыць, як адзін контэкст для всей праекта несе інфармацыю пра текущаг адвітара, тэму, колькість непрачытаных прыемаў, видимасць бокавай панелі, локацыю, флагі функцый, правыя доступу і калькую працэўных функцый. Гэта здаецца апрантным — адзін прадастар, адзін спецыяльны Hook для яго выкарыстоўвання.
Але з точкі казу апдэйтаў гэтыя значэнні не раздзеляюць аднойчы ўсю адпаведальнасць. Колькість павестак можа апдэйтавацца колькіразоў у хвіліну; тэма можа застацца незменной прынямна месцы. Візыбельнасць бокавай панелі — це локальны стан UI, тады як інформацыя аб автэнтыфікованам корыстніку відбівае саму сесію. Адзінавэнне іх значыць, што кожны корыстнік фактычна падпішаецца на змяны, якія можа ўзагалі не цікавяць.
Часта прадаўець таксама перзбудоввае свое значэнне контексту праз кожны рендар:
function AppProvider({ children }) {
const [theme, setTheme] = useState("light");
const [notifications, setNotifications] = useState([]);
const [sidebarOpen, setSidebarOpen] = useState(false);
const value = {
theme,
setTheme,
notifications,
setNotifications,
sidebarOpen,
setSidebarOpen,
};
return (
<AppContext.Provider value={value}>
{children}
</AppContext.Provider>
);
}
Кожны раз, калі прадаўець перарэндавае, value становіцца абсалютна новым об’ектам. Корыстнікі бачаць гэта як змяну па ссылцы, нават якщо конкрэтны поле, яке ўони чытаюць, на самай працэ нічога не змянілася.
Зберагчыце значэнне, якое перадаецца прадастку, можна запобiec павтарэнню перрэндераў, вызваным апцэнкай несувязанага вышэйшага элемента, але гэта не дазволяе раздзеліць значэнне контекста на незалежныя часткі. Як толькі змянююцца паведамлення, весь сумарны об’ект все равно лічыцца як зменены.
Кращы падход — раздзеліць контекст па лініях адпаведальнасці та частоте апцэнкі, а не за прыемнасцю наявнасці аднаго файла прадастка. Канфігурацыя, якая рэдка сьвічаецца, можа знаходзіцца ў аднам контексте. Данныя, якія шыбка змінююцца, можаць мець свой сабстантыўны контекст. Стан локальнага макету можа ўзагалі не патрабаваць праходжання через контекст усіяго застосунка.
Контекст — гэта не толькі механізм перадачы значэнняў, але і механізм распадзелу апцэнкаў. Тое, як формуецца значэнне прадастка, вялічына таго, на якую вядома кожная змяну.
3. Перзбудова об’ектаў, масів і функцый, калі ідэнтычнасць дзейсна мае значэнне
Стварэнне новых значэнняў праз кожную перрадзіцю ёсць звычным падходам у JavaScript. Адразу ствараны об’ект, фільтраваны масэвак або новая функцыя-стрэлка зазвычай купуюцца за мінімальную цэну, таму спробы ўтрымацца ад іх викорыстоўвання нічога не даюць.
Справы становяцца складнейшымі, калі якая-небудзь наступная логіка вырашаецца на ідэнтычнасці значэння, а не толькі на яго ўмесце.
Об’ект, які быў зберажаны ў памяці, пераглядае свае параметры праз рэферэнс. Компонент типу Effect пераглядае свой список залежнасцей таксама праз рэферэнс. Компонент таблы можа перзбудаваць своія внутранія структуры ўсякі раз, калі змінюецца рэферэнс масэвака з коламі. Прадастальнік контексту павярамляе сабэрэнтаў пра апдэйт, калі значэнне, якое ён трывае, паказвае на новы рэферэнс.
Два об’екты можу хаваць ідэнтычныя даны, пры тым заставаючыся двума рознымі об’ектамі ў памяці. Якщо дзецінскі компонент на кожную перрадзіцю родныя компанеты отрымае абсалютна новы об’ект налашоўкаў, ён не можа знайсці спосабу даказваць, што нічога з тых налашоўкаў фактычна не змянілася.
Звычайная рэакцыя — гэта адразу ўвесь час паказваць кожны об’ект у useMemo, а кожную функцыю — у useCallback. Аднак гэта проста заменяе адна рэфлектыўная прычынка на іншую. Мемаізацыя не ўжо безкоштовна — у яе є сопрацоўнічы трыбут, свой массив залежнасцяў, які трэба падтрымваць, і свои витраты на адтульненне. Яна стае корыстной толькі тады, калі стабільны рэферэнс дазволяе ухіліцца ад викорыстання дорогіх ресурсоў чы ўзнавісць іх.
Значэнні, якія ніколі не зменяюцца, часта можна задаць вантолькі за межамі компонента. Уместа таго, каб з цых прычын адразу паклаць калькі пропсаў у адны об’ект, дзецавы компонент часта можа проста получаць адпраўныя значэнні безпосередна. Функцыю трэба стабілізаваць толькі тады, калі яна викорыстоўваецца ў Effect, падпісцыі чы мемаізацыйным механізме, дзе ідэнтычнасць справаўіць рэальны вплыв на ўзрасленне.
Праўя працэзная перакананне — глядзець, што выходзіць з-за новага кансэнту. Якшто ніхто пасляэтапна не зважае на гэта, перзначэнне значэння ў кожны раз падчас атрыбутавання не шкодзіць. Але якшо новы об’ект спрычыняе перзбудову великай табліцы або прыводзіць да роз’ўязання падпісу і ўтварэння яго зноў, тады ідэнтычнасць гэтага об’екта стае часткай умов кантракту на працэзную эфективнасць компонента, і ёй трэба ставіцца адповідна.
4. Зберагчыце вырахаваныя значэння і падтрымайце ў яных актуальнасць за дапамогою эфектаў
Адным з наіменш очывічных джэрел дадатковага атрыбутавання є зберагчыце частку статаусу для таго, што можна проста вырахаваць з існуючых прапсоў або статаусу.
Разглянем компонент, які вы калечае цэлы спіс запісаў, тэкст текущаг фільтра, а таксама окрема, зберажаная фільтраваная ліста. Альбо форму, якая фіксуе свае поля, памылкі верыфікацыі, а таксама самастоятельны флаг canSubmit. Альбо компонент ліста, які зберагае як выбраны ідентыфікатор, так і другую значэння стану, якае вы калечае адпаведны выбраны об’ект.
Пакалькі гэтае дублюванае значэнне можа выйсці несінхронным, разработчыкі дадаюць Effect, каб яго падтрымліваць у актуальным стане:
function Products({ products }) {
const [search, setSearch] = useState("");
const [visibleProducts, setVisibleProducts] = useState(products);
useEffect(() => {
setVisibleProducts(
products.filter((product) =>
product.name.toLowerCase().includes(search.toLowerCase())
)
);
}, [products, search]);
// ...
}
Так адбываецца, калі змінюецца search: спячынача компонент атрыбутуеўваецца з застарэлай фільтраванай лістаю, якая ўсё ще знаходзіцца ў стане; React фіксуе гэты атрыбутаванне, пасля чаго запускаецца Effect, які аднавляе стан і плануе ўсё новае атрыбутаванне.
Гэтае другае атрыбутаванне існуе толькі таму, што рэзультат вычыслення быў зберажаны так, нібы яно было незалежным элементам стану.
Якщо visibleProducts вычысляецца безпосередна пад час атрыбутавання, ён автаматычна застаецца сінхронным, і зайвыя процесы атрыбутавання зьнікаюць цалкам. Калі логіка фільтрацыі є даскладной, можна загорнуць вычысленне ў мемо, ключаванае па яго рэальных вхідных данных. Галоўнае — такая мемаізацыя заховвае толькі результат вычыслення; яна ніколі не должна ператвараць захаваны рэзультат у другы, незалежны ад іншых джераг правды.
Этот патэрн мае наследкі не толькі у вачынцы зайвых процэсаў атрыбутавання. Працягнуты стан можа на короткі час паказваць значэнне, яке суперсачыцца з його вхіднымі даннымі, а складанне калькольных ефектаў можа спрычыніць адгульную пэрэатрыбутавання. Адзьёмлена зайвая становасць зазвычай адзьёмляе ўзмацнілія сінхронізацыі таксама.
5. Падпіска на больш чым неабходнае колькасць зовнішняй базы дадзеных
Бібліятэкі стану, які керуюцца селектарамі, можа даць дужа цялевыя апдэйты, але толькі тады, калі компаненты насправдзе выбіраюць вузкія, конкрэтныя значэння.
Часты спосаб — абонавантажэнне на цэлы склад, або на одны большы об’ект на рэвэлеўнай адзіне, а пасля выкарыстоўванне толькі аднаго поля. Гэта значыць, што компанент перарысваецца ўсякі раз, калі змянюецца ўсё, што знаходзится внутры таго большога об’екта — нават поля, якіх ён ніколі не чыпае.
Гэтая проблема нейкім чынам не ўнікальная для бібліятэк керування станам. Яна таксама выступае з кэшамі для запоўнення дадзенаў, системамі на адной змагальнасці і ручнымі хукамі абонавантажэння. Чытанне з большага джерела чыста з прыкметкі робить компанент рэактывным на наблыжае больш змян, чым яму трэба.
Тое, які стан тэхнічна мае право абраны компанентам, — гэта не тая ж самая пытанне, як і тое, які частака гэтага стану мае право спрычыніць яго перарысванне.
6. Нестабільныя ключы, які таямніча прыводзяць да павтоваго запуску компонента заместо апдэйтаў
Павтапрацоўка запускае компонент зноў, захоўваючы його ідэнтыфікатор, локальны стан і пазицыю недзеянымі. Павтовы запуск делае іншае — ён знімае існуючы экземпляр компонента і стварае новы з нуля. Павтовы запуск зазвычай ўсё болей дорогі, адтолькі як React больш не можа перысваяць пярэйшы локальны стан, існуючыя звязкі DOM чы ўсе рэсурсы, прыяўязаныя да жыцёвага циклу компонента.
Ключы, якія не ўстойкі, могу таямніча ператварыць тое, што мяжваў быць простымі апдэйтамі, на павтовыя запускі.
Якщо ключ апраначваецца за дапамогою случайнага значэння, тэрміналу часу чы поля, якое зменяецца пад час рэдагавання элемента, React спрыямае гэта як абы стары элемент цалкам знік. Паколькі кожная павтапрацоўка стварае разны ідэнтыфікатор, пярэйшы элемент выкарыстоўвання знімаецца, а на його месцы запускаецца абсалютна новы.
Частаючы, видны сімптамы з’яўляюцца раней, чым хто-небудзь восьбі з’являе проблему з выконаннем. Поле для вводу тексту тыячае фокус пад час напісання, розгорнутыя рядкі знову закрываюцца, анімазыі пачынаюцься значна зноў, а стан локальных компонентаў зникае. Вплыв на выкананне стае серьёзным, калі перезапускаемыя компоненты выканаюць болей складную настройку — ініцыялізацыю редактароў, дыяграм, абзэрватараў, падпісоў, прагравачаў медыя або запитоў да сеті.
Іспытанне індэксаў масіва як ключоў стварае болей тонкую версію гэтай проблемы, калі элементы ліста можна пераранжаваць, дадаваць або выкасываць. React можа заставіць стан компонента прыязначаны да паводзячага месца ў лісте, нават якщо тэпер іншы элемент займае гэта месца. Гэта несувярозумеласць можа спрычыніць прыязначэння стану да неправильнага элемента і вымусіць некалькі непатрэбных дзеяння з узгоджэнням, усё гэта таму, што ключы на самай працоўцы не відбіваюць стабільныя ідэнтыфікаторы элементаў.
Якша выбраны ключ должен выражаць стойкую ідэнтычнасць элемента ў яго спісе. Ён павінен змянювацца толькі тады, калі элемент трэба спрацавляць як абсолютна іншы экземпляр — а не проста таму, што адбылася перрадараванне.
Існуюць законныя ситуацыі, калі намераваная змена ключа є правильным спосабам, адколі гэта змушвае React перазначыць цэлую паддрэву. Гэта павінна быць свядомая выбор, адколі гэта означае відмову ад усьго, што React раней зберагаў для той паддрэвы. Ненамераваная перзапуск здаецца набагато дорожэй, чым звычайна перрадараванне, і лёгка працязіць не зазначыць, калі выраз ключа на першы погляд здаецца нейкім.
7. Залічванне важкіх інтэрфейсаў, калі яны не ў візуальнай зоне
Компанента не павінна быць візуальна доступная, каб продаўаць свою роботу.
Карточкі, шухляды, модальныя вікна і складываецьяя панелі частаўка залишаюцца установленымі, але візуальна схованыя за дапамогою CSS, адколькі такой падход зберагае внутршній стан і дазволяе інтерфейсу мгновенна зноў ачыніцца. Для лёгкага кантэнту такы компроміс часта є разумным.
Аднак для большых інтерфейсаў застава ўстановленымі значыць, што яны можу продаваляваць контекст і зовнішніх сховішчаў, продаваляваць новыя параметры, продаваляваць перерасчэты і падтрымліваць свае эфекты — усё гэта, калі корыстнік не можа бачыць рэзультата. Панель керавання можа заставіць калькюляцыі графікаў у цэлым актываным стане за карточкамі, якія ніхто зараз не адглядае. Рэдагувальнік, спрывязаны ў схованай панелі, можа продаваляваць обробку апдэйтаў дакумента на фоне. Дыялог, які быў візуальна закрыты, все ўсё можа заставіць сабе вялікую структуру формы разам з логікаю пераканання.
Ваша аплікацыя плаціць рэальную цену за гэта, таму што React яшчэ тратыць той падвёсны паддрэс як частку адпаведных шляхоў выкарыстоўвання для адрасавання. Значэнне display: none прыменяецца толькі да таго, як браузер распаковвае элементы — гэта не вплывае на тое, чы рэакт яшчэ керуе і апдейтуе тым паддрэсам.
Протыма, адключэнне кожнага схованага элемента інтэрфейсу таксама не є автоматычна правым рашэнням. Перзначальная нарадка масівага рэдагувальніка з нуля ў кожны раз, калі корыстувач пераходзіць на іншую вкладку, можа зробіць працэс медленнейшым, а таксама можа стерць стан корыстувальніка, які павінен застацца незмянным. Гэта, што мае значэння, — граматычны выбор на адной з основ жыцёвага циклу компонента і на адной з практычных вартасцей яго роботы.
Адзін з вароў — адкластыць падключэнне большога панелі да моменту яго першага актывацыя. Тыя элементы, якім даслівна трэба выжыць пад час візуальнага ад’ўязвання, можна разместіць у меншым, спецыяльным прыёмніку, пакуль сама структура дадзеных не зникне. Дзеяныя прылады знаходзяць ся на середзінным шляху, залишаючы падключэннымі толькі найболей неякшыя панелі і зваліваючы рэшту.
Настоямы вопыт — не тое, чы гэты элемент зараз выклікаецца на экране. Це тое, чы ён все ж такі должен прымляць і реагаваць на апдэйты, калі ён не выклікаецца на экране.
8. Дазвол на паўтарны запуск эфекта з-за нестабільных залежнасцей
Эфект, які залежыць ад певнага значэння, будзе чыставацься і запускаться занова ў кожны раз, калі гэта значэння змянюецца — і гэта абсалютна правільна, калі зовнішняе адноса, якое представляе эфект, даслівна змянілася.
Проблема заключаецца ў тым, што нестабільныя залежнасці можу ствараць вражанне, што гэтыя зв’язкі змінююцца праз кожную перрадарацыю, нават калі на самай працэ не відбываецца нічога значныя.
Разглянем компонент, які стварае об’ект з параметрамі і передае його спецыяльнаму Hook, які пасля таго викорыстоўвае гэты об’ект як залежнасць для Effect. Паколькі родны компонент стварае абсалютна новы об’ект праз кожную перрадарацыю, Effect постаянна руйнуе свой зв’язак і знова яго стварае. Аналогічна ситуацыя выклікаецца, калі працэўнік падзейства ствараецца занова праз кожную перрадарацыю і викорыстоўваецца як залежнасць для эфекта-слухача, што прыводзіць да таго, што гэты слухач неўпінно адключаецца і знова падключаецца. Об’ект налаштавання запыту можа спрычыніць стварэнне новага запыту ў кожны раз, нават якщо жадных значных полей у ўсём працэ не змінілася.
Такі додатковыя навантажэння не завжды выражаюцца як проблемы з адрасаваннем. У замест на гэта яны практыкуюцца у відпавах подвойных запытоў да сеті, шырокамасштабным ачынанні та закрыцці з’ўязкаў, мерканні інтэрфейсу або зьнікненні та павтарным праказаннем слухачаў зьвярэнняў. Што ўжо горш, такія перачынення эфекта часта самі вызываюць функцыі для змены стану, што спрычыняе дадатковыя адрасаванні, якія маскуюць первінную прычыну проблемы.
Рашэння не ў тым, каб проста адмахнуцца ад залежнасцэў у масі, толькі каб стымулюваць меншае колькасць паведамленняў пра проблемы. Залежнасці існуюць для таго, каб точна апісаць, якія значэння чытае эфект, а ўсуненне одной з іх прыводзіць да старых клаусураў та нарушэння сінхронізацыі.
Лепшы варыянт — даць залежнасці стабільную ідэнтычнасць, калі саме яна мае значэнне. Залежна ад ситуацыі, вы можете стварыць об’ект у самам Effect з прымітных значэнняў, стабілізаваць калебак, ўбачыўшы, што яго не трэба перзаснавляць праз кожны рендер, або зрозумець, што гэтая логіка вовсе не належыць у Effect, і перашырzyć яе ў працоўнік змагання.
Effect павінен перазапускаться тады, калі зовнішняя система практычна выклеквае новую сінхронізацыю — а не тады, калі рендер випадкова стварыў іншы функцыйна ідэнтычны об’ект.
9. Замена стану на новы об’ект, які выражае тое ж самае
Залежна ад таго, як React пораўнюе значэння, іноды можа праскочыць перзапісве, калі наступны стан адпавядае нынешнему. Але для об’ектаў і масэв, якщо да React падае новая рэферэнцыя, стан выглядае інакша, нават калі яго фактычныя элементы вказуюць на тое ж самае.
Гэты патэрн часта з’яўляецца ў обрабочыках запуску іяўанняў і логіцы хранення дадзенаў. Фільтр перазначаецца на абліковы об’ект, які фактычна ўзаемна адпавядае таму, што вэсці ўжо было. Редюсер вяртае нова створаны об’ект стану для дзеяння, якое нічога не зменіла. Адпаведнае адказа з польсінгу копіюецца у новую масэ, нават якія ўсе елементы ў ёй застаюцца незменнымі.
У React няма загальнага спосабу самастойна выканаць перакананне ў глыбокай сэмантичнай роўнасці. Як толькі той, хто керуе станам, вяртае новы об’ект, React спрацьвоўвае гэта як значымую апдэйт, яку трэба обрабаваць.
Ёнколі ўздзейсненне якой-небудзь дзеяння на самай працэ не зменшыць стан, редюсеры должны вяртаць існуючы об’ект стану, каб ухіліцца ад гэтага. Функцыі для змены стану могу прайслаць значэнняя, якія маюць значэнне, прычым перад тым, як заменіць цэлы структурованы об’ект. Слоі, якія адпаведная за нормалізацыю прыходзячых дадзенняў, могу застаўляць тыя ж рэферэнсы для записаў, якія не змениліся, у працох ад перабудовы цэлага калекцыі з нуля пасля кожнай адпаведнай дзеяння.
Усё гэта не значыць, што трэба адмахоўна прайслаць кожную зміну стану. Адмахоўная прайслаць можа выйсці дорожэ, чым тое, чаго яна намагаецца запобiec, і ўводзіць яшчэ адну концепцыю „роўнасці“, якую тепер трэба сталеліва падтрымліваць. Болей стойкі падход — гэта прыродна застаўляць ідэнтычнасць об’ектаў, калі адпаведныя дадзення на самай працэ не змениліся.
Структурныя спільнання — гэта тое, што дазволяе React, а таксама всім мемузаваным элементам, якія знаходзяцца нижэй у лесе, розразліваць справжнія змены ад павтарэння той самай інформацыі. Новая рэферэнца должна сигналізаваць пра новы стан — а не проста пра новая распадзелка памяці, якая зберагае тыя ж значэнні.
Мета не ў тым, каб усунуць павтарэнне адрасавання
Програмы на React стаюць швэдкімі не таму, што адмовляюцца адрасаваць элементы. Яны стаюць швэдкімі таму, што процес адрасавання фіксуе значымыя змены і обмежваецца тымі часткамі леса, якія дэйсна павінны переглядзець свой выхід.
Перзапуск невялога, простаг компонента частае выгодней, чым стварэнне і падтрымкі складнага механізма мемоізацыі для яго. Апдэйт контексту, які паўтараецца толькі над калькамя лёгкіх корыстнікаў, можа ўзагалі не патрабаваць жадных архітэктурных змян. Рашэнні ў паводзе працоўнасці должны базавацца на рэальных затратах на взаімадзеянне, на аналізе эфектывасці і на масштабе, якога вы фактычна спадзяваецеся — а не на абсалютным прагоне запобегаць рэндэраванню, дзе толькі можна.
Вышэпісаныя прычыны ўскладненняў выклікаюцца саме тым, што яны паступова расшыроўваюць межы таго, што аптэльнуюцца. Чырпанне статаусу на занадта высокі рэвэл прыводзіць да таго, што маленькая, локальная взаімадзея ператвараецца на задачу, якая распрастраняецца па всій сторанцы. Шырокі контэкст і падпісвы на сховішчах распространяюць некалякуюцыя змены ў компаненты, якім не трэба было пра іх ведаць. Нявечна створаныя рэферэнсы прыводзяць да таго, што стабільныя данні выглядаюць інакш ад адной рэндараўкі да другой. Працяванне статаусу, які выведаецца з іншых даных, у поўнасці разам з ефектамі можа спрычыніць серію дадатковых аптэльнаўкаў. Нестабільныя ключы унемагчамляюць павторнае викорыстанне дадзеных і прыводзяць да ўсёполных перыяднаўкаў. Скрытыя паддрэвы продовжаюць выканаць роботу, яку ніхто не можа бачыць, а статаус, які ў структурным сэнсе ідентычны, продовжае атрымваць статус абсалютна новага.
Мемаізацыя можа справжньяму дапрацаваць, калі гэтыя адносы будуць правильна зрозумелы. Яна працюе найэфектывней, калі межы вашага компонента, адпаведная ўласнасць стану і ідэнтыфікаторы кансаляцый вже самі па сабе маюць сэнс. Без такой базы мемаізацыя становіцца проста захоўнай шаром, які абгортае граф актуалізацый, які ўсё раван неабходна вялікі.
Найпрыдатнейшы вопыт, які трэба задаць пра выдатнасць React, — гэта не «як мне запобiec адрасаванню гэтага компонента?»
Это «шта на самай працоўкі змянілася, хто ёсць власнікам гэтай змяны і чаму ад гэтага компонента патрабавалі знову пераглянуць сябе?»
Калі у вас будуць чыстыя адказы на гэтыя вопыты, значны частака непатрэбных перадрукаванняў зазвычай зникае сама сабою — без таго, каб вашыя дрэвы компонентаў ператворыліся на заплутанае скупшча кэшаў і функцый паўтарнага порэвання.