Складзіце прычыны, выведзіце наследкі: проектаванне мінімальнага стану React
Навучыцеся выявляць зайвы стан React, заменіце ланцюгі сінхронізаціі, якія керуюцца функцыяю Effect, а таксама булевыя флагі на выведзеныя значэння і аб’еднанні статусаў, і выберыце, дзе должен знаходзіцца стан.
Большасць компанентаў React не становяцца складнымі для змены чераз адну пасляпэтную рашыць. Яны поступова прыводзяцца да такога стану праз адну за адной разумна выглядаючую вызову useState, пакуль тая ж самая інфармацыя зберагаецца ў трох месцах, і ніхто не можа сказаць, якая копія є автантонійной. У гэтым нарадчыку рассказваецца пра рэалістычны список продуктав, які падпадае пад гэтыя проблемы, а потым паказваецца, як вярнуцца да рашэння, што саме должен памятаць компанент, што ён должен вылічваць за кожны рэндер, і дзе павінна знаходзіцца кожная застаўшаяся частка стану. До канца вы будете мяць конкрэтны чарточку перагляду для адсортавання стану, прычым яны не ператвараюцца ў багі сінхронізацыі.
Як просты список продуктав накаплівае стан
Уявіце сабэйфу адміністратара, дзе пераказаны тавары. Люди можаць увести назву для пошуку, скаржыць спіс на адну катэгорыю, сортаваць па цэне, выбраць адну тавару і бачыць, сколькі элемента засталося. Першая версія зберагае толькі тое, што увёў і выбраў корыстнік:
function Products({ products }) {
const [search, setSearch] = useState("");
const [category, setCategory] = useState("all");
// ...
}
Потым прыходзяць запиты на дадатковыя функцыі. Табліца павінна адобразваць тавары, якія падходзяць, таму хтось дадае зменную стану, якая зберагае фільтраваны спіс:
const [filteredProducts, setFilteredProducts] = useState(products);
Лічылка над табліцай паказвае, сколькі тавароў падходзяць, і гэта число таксама мае свой стан:
const [resultCount, setResultCount] = useState(products.length);
Калі нічога не падходзіць, сторанка павінна паказаць прыемліве поведамленне, таму для гэтага таксама стварываецца флажок:
const [hasResults, setHasResults] = useState(true);
Далей выканана сортаванне, якае включае выбраны критэрый сортавання і сортаваную копію спісу:
const [sortBy, setSortBy] = useState("name");
const [sortedProducts, setSortedProducts] = useState(products);
Кожна змянення є незначнымі і легкія даюцца затвердзіць пад пераглядзе. Але чырвоныя тыжні пасля цього пачынаюцца адзін за адным. Пераключэнне катагорыяў іноды паказвае правыя рядкі пад неправым колькасцю. Адчысцэнне поля пошуку на момент паказвае запаведзенне „нэт канкрэтных рысункоў“. Калі новая адпаведзь API прыносіць новыя products, табліца продовжвае паказваць застарэлы, фільтраваны список, пакуль корыстнік чаго-небудзь не нажме.
Компанента заполнена станамі, пры тым яна больш не можа адпавесці на ўсёга важнейшы вопыт: каторы з гэтых значэнняў є справжнім?
useState не ў вінаватасці. Проблемы пачынаюцца тады, калі компонент зберагае калькольванні колькасць версый інфармацыі, якія ўсе маглі б быць вычыслены з меншага набору основных фактов. Кожная дапаможная зберажаная значэнне — это ўсё тое, што трэба падтрымліваць у суворай адпаведнасці з іншымі, а самэ гэта і робіць простыя компоненты кранкаватымі.
Кожная зберажаная значэнне — это ўсё той спосаб, як можна памыліцца
Компонентам патрэбны станы, таму што часть інфармацыі павінна застацца між перзапускамі: тэкст у поле вводу, актыўная карточка, чы розкрываецца модальное вікно, яю строчку выбраў корыстнік. Гэта ўсе є природнымі варыянтамі.
Памылка заключаецца ў тым, што спрыймаюць факт "гэта показваецца на экране" як значэнне "гэта павінна быць зберажана". Паглядзіце знову на сторонку товара, дзе кожна значэнне зберагаецца ў стане:
const [search, setSearch] = useState("");
const [category, setCategory] = useState("all");
const [filteredProducts, setFilteredProducts] = useState(products);
const [resultCount, setResultCount] = useState(products.length);
const [hasResults, setHasResults] = useState(true);
Кожная зменна мае разумную назву, але яны не ўзаемна незалежныя. Фільтраваны список залежыць ад трох вхідных дадзенняў:
products + search + category
Колькасць залежыць ад фільтраванага списку:
filteredProducts.length
А флажок стану «пусто» залежыць ад колькасці:
resultCount > 0
Калька справжніх фактов была розгледзена як калька кількох збераганых наследкав. Гэта адкрывае можлівасць для комбінацыяў, якія інтэрфейс не должен быць у стане паказаць, напрыклад, такія:
filteredProducts = []
resultCount = 4
hasResults = true
React з радасцю будзе зберагаць гэтыя значэнні. Вы адзначылі тры незалежныя часткі стану, таму React спрацоўвае з імі як з трыма незалежнымі часткамі стану. Падтрымка ўзаемнай логічной супараднасці — цэлкам задача вашага прыемніка, і кожны обробнік запуску, який вплывае на адну з іх, должен памяцать пра іншыя.
Дакументацыя React радзіць утримвацца ад зайвага і дублюючагася статау самэй гэтай прычыне: калі значэнне можа быць вылічана з props або іншага статау пад час рэндара, яго разамо зберагачы дае толькі новую можлівасць для несуразнасцей у копіях.
Вывад не ў тым, каб «выклікаць useState менш часта». Це змена таго, як вы розумееце статау:
Памятайце факты, якія компонент не можа восстановіць іншым способам. Вылічайце все, што вынікае з іх.
Зберагачыце ввод у статау, а рэст вылічайце
Сторонней сторунке ніколі не было патрэбы памятаць resultCount. Яе трэба памятаць тое, што корыстувач увёў у поле пошуку і якую категорыю выбраў. Это выборы, здзейсненыя чалавеком, і ніч у дадзенах продукту не можа ўсё гэта восстановіць. Усе інша вынікае з гэтаго:
function Products({ products }) {
const [search, setSearch] = useState("");
const [category, setCategory] = useState("all");
const filteredProducts = products.filter((product) => {
const matchesSearch = product.name
.toLowerCase()
.includes(search.toLowerCase());
const matchesCategory =
category === "all" || product.category === category;
return matchesSearch && matchesCategory;
});
const resultCount = filteredProducts.length;
const hasResults = resultCount > 0;
// ...
}
Зверніце увагу, што зникло. Не трэба адканалізаваць resultCount; у hasResults няма функцыі для змены значэння, і больш не існуе ситуацый, калі які-небудзь прыемнік апдэйтуе фільтраваны список, але забывае про колькасць элементаў. Кожная перрадка проста павтарна вырахоўвае рэзультаты на аднойчынных даных. Новая строка пошуку стварае новы список, новая катэгорія таксама стварае новы список, а якщо родны элемент передае іншы масів products, то вырахунак проста выкарыстоўвае гэты масів.
У компонента тепер менш зменных, якія можна запісваць, і гэта ў дзесяткі разоў значышлівейшая паліпшэння, чым проста менш ліній коду. Праўедзенае значэнне все ўсё можа міць логічныя бяглы, але яго ніколі не можа стаць застарэлым чераз тое, што якісь прыемнік забыў яго апдэйтуваць. Гэта усунула цэлую групу станоў, да якіх компонент раней мог ўявіцца.
Документацыя React ілюструе тую ж ідэю за дапамою fullName, які складаецца з імені та празвішча: якщо можна вылічыць його пад час відрисавання, додатковая зменная стану нічога не дае, а толькі павышае рызык нэсувязанасці.
Швыдкі тэст, які можна застосаваць пад перагляд коду:
If I deleted this state variable,
could I reconstruct its value exactly
from current props and other state?
Якщо адказ — так, спачатку ператворыце цэ на просты вылічэння. Стан існуе для зберагачвання інформацыі, а не для кэшавання кожнага проміжнага рэзультата, які компонент випадкова стварыў па дорозе.
Калі useEffect становіцца канвею сінхронізацыі
Звычныя дзеяння ў разе застарэлага похаднага стану — це вжыць useEffect, ўбліжчаючы копію да актуальных даных. Тады компонент product стае ў такім виглядзе:
const [filteredProducts, setFilteredProducts] = useState(products);
useEffect(() => {
const nextProducts = products.filter((product) => {
const matchesSearch = product.name
.toLowerCase()
.includes(search.toLowerCase());
const matchesCategory =
category === "all" || product.category === category;
return matchesSearch && matchesCategory;
});
setFilteredProducts(nextProducts);
}, [products, search, category]);
Далей другі эфект падтрымлее колькасць у сувязі зі спісам:
useEffect(() => {
setResultCount(filteredProducts.length);
}, [filteredProducts]);
А можа трэці эфект керавае флагам порожньяго стану:
useEffect(() => {
setHasResults(resultCount > 0);
}, [resultCount]);
Ўныя разам утвараюць невялікую внутранюю лінію обробкі:
products/search/category
↓
filteredProducts
↓
resultCount
↓
hasResults
Жадны з эых крокаў не вяршыць нічога за межамі React. Яны толькі ператвараюць значэнні, якія ўжо знаходзяцца ў React, і гэта разлік являеся сутнёю прыблуды. У дакументацыі React эфекты рассматрываюцца як спосаб перашчыпнуцься, калі трэба падтрымваць компонент у сувязі з чымось, чаго React не кантролюе, такім як API прыгледача, сокет або відэльнай прыблуды. Калі эфект існуе толькі для таго, каб змяніць адзин элемент стану компонента у адпаведнасці да іншага, сучасныя рэкамендацыі заклёваныя у тое, каб запытацца, чы рэальна потрэба ў тамтым другім элементе стану.
Існуе такса працы часу выконання, яку лёгкая перакінуць. Кожны эфект выконваецца пасля таго, як React вже завершыў процес атрыбутавання, таму кожны элемент ланцюга спрыяе ўтварэнню новага атрыбутавання з часткова апдэйтаванымі значэннямі. Саме звядзе гэта прычына кароткага моманту „жадных рэзультатаў“ у пачатковай сценарыі: пад час атрыбутавання новы список вярнуўся, але флаг усё щэ паказвае старую колькасць.
У версіі, якая выраховываецца, ланцюга вообща няма:
const filteredProducts = filterProducts(
products,
search,
category
);
const resultCount = filteredProducts.length;
const hasResults = resultCount > 0;
Это не проста якіснейшая сынтаксіс — гэта таксама змянюе спосаб прымышлення. За дапамою збераганага похадзяглага стану вы фіксаваеце, калі была востаннўя змянена кожная значэнне, чы рэлевантны Effect вже выконваўся, чы його массив залежнасцей ўжо заполнены, і чы іншая апдэйтаванне ўсё яшчэ чакае пасля яго. Пры вырахунку вы думаеце пра вхідныя та выходныя даны, і для чыстых трансфармацый гэта набліжна простыяй модель для падтрымкі. Якщо ваш кодбаза вже мае Effects такага типу, пасляэтапная рефакторка, описаная ў Stop Syncing State with useEffect, паказвае, як безпечна ўсунуць іх.
Заменіце булевы флагі на адны статус
Дуплікаваныя значэнні — гэта адна з форм перадмерклага стану. Іншая ситуацыя выступае, калі адна концэпцыя розпадаецца на кальколька незалежных булевых значэнняў. Класычным прыкладам є адправка формы:
const [isIdle, setIsIdle] = useState(true);
const [isSubmitting, setIsSubmitting] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
const [isError, setIsError] = useState(false);
Процес должен выконвацца толькі ў аднай з чатырох фаз:
idle
submitting
success
error
Аднак чатыры логічныя зменныя можу выражаць шысць комбінацый, і багатыя з іх ўзгодныя. Форма можа адразу ствараць вражанне, што яна надасіла даны і ўжо досягла успеху:
isSubmitting = true
isSuccess = true
Альбо яна можа адночасна паведамляць пра успех і нявыполненне:
isSuccess = true
isError = true
Альбо кожная зменныя можа мець значэнне false, што не адпавядае жадной з фаз. Інтерфейс можа ніколи навмысна не ствараць такія комбінацый, але структура дадзеных гэта дазваляе, таму недастатак вызову функцыі-зменнікай у аднам з обробнікаў дастаткова, каб досягнуць такога стану. Рэкамендаціі React па структураванні стану прымусова рэкамендуюць утрымацца ад такіх суперсчыненняў і зменшыць колькість змянных, якія дазваляюць выражаць немагчымыя станы інтерфейсу.
Адзін значэнне статусу описвае гэтыя панорамы набліжна точней. У TypeScript аб’яднанне з літераламі строк таксама дазволяе кампайлеру адхіляць падбіяння і неканонічныя стадыі:
type Status =
| "idle"
| "submitting"
| "success"
| "error";
const [status, setStatus] = useState<Status>("idle");
Зручныя логічныя значэння застаюцца доступнымі, тепер як выведзеныя значэння:
const isSubmitting = status === "submitting";
const isSuccess = status === "success";
const isError = status === "error";
Разлік выглядае незначным, але ён фундаментальны. Першая версія вымагае, каб ваш код падтрымляў чатырнаць фактов у сувязі. Другая зберагае адзін факт і чытае чатырнаць його версій.
Корыста зрастае ў меру розгародкі. Процес выкаупа можа праходзіць через гэтыя стадыі:
editing
validating
submitting
confirmed
failed
Імпортар файлоў можа праходзіць через гэтыя:
idle
uploading
processing
completed
failed
Калі компанента мае режымы, якія адзін з іншымі выключаюцься, павінна гэта адзінаковасць стаць часткай модэлю стану, а не правілам, якімы павінны следаваць усе обрабоўчыкі. Яны самі вяршаюць рашэнне, якія станы можа представляць програма, і гэтае рашэнне трэба прыменяць з той жа адзінаковасцю, як і сам маркап. Є адна прыметка: калі якась фаза несе данні, напрыклад, паведамленне пра адзію, якае існуе толькі ў фазе failed, аднасць об’ектаў з дзяленнем дапамагае заставіць гэтыя данні пры належной фазе, замест таго каб дадаць ўтрымкі іншую вольную зменную.
Меньша колькасць змянных — гэта не тое ж сама, што адзін вялікі об’ект
Калі каманда чуе фразу "зменшыць стан", прываблівайшым перэконтролем яе ўсё падаць у адзін об’ект:
const [state, setState] = useState({
search: "",
category: "all",
selectedProductId: null,
sidebarOpen: false,
page: 1,
});
По замовчэнню гэта не ўлучшэнне. Адзінальныя вызовы useState не маюць значэнага каштоўнасці, таму мінімізацыя ўжо існуючых колькасці не являецца метай. Мэтая — чыста прадставіць незалежную інфармацыю та утримацца ад двойнага зберагання той самай інформацыі.
search та category зміняюцца па своіх графіках, а sidebarOpen не мае нічынага з жадным з іх. Храненне іх як адзінальных змэнных робіць кожную апдэйтаванне зрозумелым у месцы вызову:
const [search, setSearch] = useState("");
const [category, setCategory] = useState("all");
const [selectedProductId, setSelectedProductId] =
useState<string | null>(null);
const [sidebarOpen, setSidebarOpen] = useState(false);
У дасведчэннях React таксама праставляюцца тыя ж правіла. Значэнні, якія завжды зміняюцца разам, можна групаваць, тады як зайвыя, суперсечныя, дубліруемыя або глыбокая спакойленыя данні трэба скасаваць. Адзіненне несувязаных значэнняў таксама мае практычны недзеянне: кожная апдэйтаванне павінна распрасцяваць пакойшы об’ект, а якщо забыць пра гэта, іншыя полькі будуць стерты без жадных супавесткаў.
Таму важным запытаннем не ёсць тое, чы можа набор значэнняў пасадзіцца ў адны об’ект. Практычна все можа. Замест таго запытайце:
Чы гэтыя значэння ствараюць адна цэлісная частка стану, чыя пераходы належаць адны да другых?
Калі так, іх групаванне можа зробіць код яснейшым. Калі нятак, адны об’ект толькі затьмарыць, якае апдэйтаванне паўтарае што. Скорачэнне стану значыць адзёрванне інформацыі, якая зберагаецца два разы, а не спрэчванне компонента ў якомога меньшыя элементы.
Атрыманне значэнняў без ігноравання выконвальных характэрыстыкаў
Вынесенне фільтраванага списку з стану часта воскрешае адзін пратыў: чы фільтрацыя тады не будзе выканана ў кожны раз, калі компонент атрымляе новы стан? Ёй і будзе выканана, і для большасці звычайных ператворэнняў гэта самэ правильнае співвяшчанне. Фільтрацыя масіва середньага розмера ўскладнена, але яе выкананне безпосередна ў кодзе залічвае компонент простым без якіх-леба значных затрат.
Якщо аналіз паказуе, што таяя ператворэнне дасправды ўскладненае, напрыклад, большы спіс, які фільтруецца і сортаваецца, вы можетэ зберагчыць рэзультат за дапамою useMemo:
const filteredProducts = useMemo(() => {
return products
.filter((product) => {
const matchesSearch = product.name
.toLowerCase()
.includes(search.toLowerCase());
const matchesCategory =
category === "all" ||
product.category === category;
return matchesSearch && matchesCategory;
})
.sort(compareProducts);
}, [products, search, category, sortBy]);
Зверніце увагу на тое, што useMemo не зменшвае. filteredProducts знову не стае станам, які можна зменіць. Ён застаецца чыстай функцыяй своіх вхідных параметраў; мемаізацыя толькі вяршыць, чы маге React перадаўжыць вжываць пярэйшы рэзультат пад час наступнага адрасавання, замест таго каб яго перысчыць. Гэта дазволяе трываліваць правільнасць і оптымізацыю як аднойчы, але разныя канцэпцыі. У дакументах React useMemo прыводзіцца строго як засоб для оптымізацыі выдатков, і паветараняецца не паслугвацца яй для забезпечэння правільнага працавання, таму што React можа адмовіцца ад вжывання зберагчытых значэнняў.
Парадакт выканання задач, які вынікае з гэтага:
First make the state model correct.
Then measure.
Then optimize expensive calculations if necessary.
Іспытанне стану як ручнага кэш-системы зміняе гэты порядак. Це дадае додатковую складнасць сінхронізацыі ўжо на пачатку, прычаму ніхто яшчэ не паказаў, што вычысленні ведуцься медленна. Таксама варта пераканацца, што у рэзультатах мемаваных вычысленняў у спісе залежнасцяў паказваюцца всі вхідныя даны; у прыкладзе вышэў sortBy паказваецца таму, што очакуєцца, што кампаратар сортавання будзе залежаць ад яго.
Разместіце кожную частку стану там, дзе спільна прыменяюцца рашэнні
Нават стан, які дзеясно патрэбны, можа стварыць проблемы, якщо ён знаходзіцца не там, дзе трэба. Падазроўваючы, што кожны ряд з товарамі фіксуе свой сабэй выбор:
function ProductRow({ product }) {
const [selected, setSelected] = useState(false);
// ...
}
Это працюе, калі кожны рядок можа быть переключаны незалежна. Аднак тепер выкліканыя вимогі: за раз можа быць выбран толькі адзін продукт. Раптам кожны з братоўскіх компонентаў заставляе сабе свой экземпляр таго, што павінна быць адной спольную правдай – а самэй, калькі продукт выбран. Калі гэтае рашэнне мае значэнне для калькі братоўскіх компонентаў, яго павінен володзець їхній абяцелы:
function ProductTable({ products }) {
const [selectedProductId, setSelectedProductId] =
useState<string | null>(null);
return products.map((product) => (
<ProductRow
key={product.id}
product={product}
selected={product.id === selectedProductId}
onSelect={() => setSelectedProductId(product.id)}
/>
));
}
Рядкі больш не зберагаюць інформацыю пра выбор ужо ўсё. Яны отрымаюць булевы значэнне і функцію-вызов, і існуе толькі адна правда:
selectedProductId
У дакументацыі React гэта апісваецца як наданне кожнаму окремаму элементу статаусу адного-едынственага компонента-власніка. Калі калькі компонентаў павінны коордынаваць свою дзеяльнась у зв’язку з адной і той жа інформацыяй, яе перанесенне да найбліжэйшага спольнага абяцелога запобегае розніканню ў їхніх копіях.
Нічыя з гэтых прычын не падкрепляе ідею размешчання всего ў корэне прыкладнення. Яўна зазначыце, што іншыя даныя павінны застацца локальнымі. Тое, чыяе падказвае паведамленне ўвідзима, не павінна знаходзіцца рылеўка з данымі аутэнтыкацыі, а палова заполнены поле формы рэдкады ўзгоджваецца з патрэбай наявнасці глобальнага сховішча. Стан легка кераваць, калі яго власнік адпавядае ступеню шырокага распадзелу адпаведных рашэнняў. Якщо яго разместіце занадта низка, компоненты будуць дублюваць тую ж інформацыю; якщо занадта высока, далёкія часты прыкладнення будуць перзапускацца праз змяны, якія для іх не маюць значэння. Знаходжыце гэтыя межы — важлівая частка хорашага дизайну стану, а Rethinking React State: Where Your Data Should Actually Live дэтальней розглядае варыянты локальных, спільных, серверных і URL-сховішчаў.
Reducer’ы арганізуюць пераходы, а не модэль
Калі компанент скарыстаець многа функцыі-зменяльнікі, стварэнне useReducer ёсць распаўзаным наступным крокам, і часта ён яшчэ й хорашым. У замене на функцыю-обрабоўчык, якая выконвае калькі скоординаваных вызоў, такіх як гэтыя:
setStatus("submitting");
setError(null);
setLastAttempt(Date.now());
вы описваеце тое, што адбылася, як адзін запуск:
dispatch({ type: "submitted" });
Редукер скарыстаець усі змены ў аднам месца, што є корыстным, калі калькі справжна адносоўных значэнняяў змінююцца адночасова. Але ён не можа зробіць так, каб зайвыя даны пересталі быць зайвымі. Гэты пачатковы стан застаецца сумнівным:
const initialState = {
search: "",
products: [],
filteredProducts: [],
resultCount: 0,
hasResults: true,
};
Збір дублюючыхся значэнняў у редукере залишае проблему сінхронізацыі недастрыгнутай; ён проста перамешчае логіку сінхронізацыі ў редукер. Кожная дзеянне можа сьогодні правільна апдэйтаваць усе копіі, але модель все равно дазволяе існаваць калькі збераглых версый той самай інформацыі, і наступнае дзеянне, якое хтось дадаў, можа працягнуць адной з іх.
Лепшы редюсер заставляе зберагаць толькі вхідныя даны:
const initialState = {
search: "",
category: "all",
sortBy: "name",
};
Спіс продуктав, які выказваюцца на экране, пасля чаго генеруецца пад выкананнем рэндара на адной з базы стану редюсера і даказальных products. useReducer ўзяты за добры інструмент, калі пераходы становяцца складнымі, але ён не заменяе болей базавага пытання пра тое, што саме компоненту трэба пам’ятаць. Адпаведзіце на гэта пытанне перш, а потым выберіце інструмент для карэткі.
Спіс пераконтраць для аналізу стану компонента
useState дапамагае прыўно ствараць стан, і гэта яснасць закрывае архітектурныя выклікі. Кожная новая зменна — это ўсё тое ж значэнне, якое можа змяніцца сама по сабе. Якщо яна дуплікуе ўжо наяўную вярсію, тады патрабуюцца правілы для падтрымкі супараднасці обох версій. Адна дуплікацыя ўпорнай, але п’ять такіх прыводзяць да заплутанасці ў лістах залежнасцяў, функцыях-змінніках, якіе запускаюць іншыя зміннікі, кодзе для скасавання значэнняў, старых дадзеных, суперсучасных флагах і бягах, якія прыходзяць на свет толькі пасля адной конкрэтнай последовальнасці клікаў. Рашэнне рэдкая бывае у вобразе прыгожэйшага механізма сінхронізацыі; часта такая сінхронізацыя вообща не патрабуецца.
Калі стан компонента продовжвае раставаць, перагляньце кожная зберажаная значэнне і запытайце ся:
- Чы ўсё гэта апрантлівае рашэнне, якое прыняў корыстнік чы система?
- Чы компоненту патрабуецца памятаць гэта між перыядамі адрасавання?
Этыя запытанні даюць вам набагато большую інфармацыю, чым проста пісьменнае выказванне колькасці хукіў. Складовая, якая зберагае васьмыя незалежныя, неабходныя элементы стану, можа быць абсалютна правільна спроектаваная, тады як складовая з трума зменнымі вже мае занадта многа, якщо двыя з іх ёсць копіямі чы наследкамі трэцяй.
Ключовыя выводы
- Зберагайце прычыны, такія як ввод корыстніка і выборы; падчас атрыбутавання вырахоўвайце наследкі, такія як фільтраваныя лісты, пісанні і флагі.
- Эфект, які проста задае стан на базе іншаго стану, ўскладнівае розумэнне і ёсць знакам таго, што другое значэнне павінна быць расчытам.
- Адаптуйце модэлі взаімнасуперактываўных режымаў у адну значэнне статусу, каб не было можлівасці представіць немагчымыя комбінацыі.
- Групаваць значэння можна толькі тады, калі яны зменяюцца разам; адна большая аб’екта не ўсё тое, што являе сабою мету.
- Іспользуйце
useMemoпасля выканання вычыслаў, і памятаце, што гэта кеш, а не аднаковы источнік даных. - Даеце спакульнаванным фактам адного власніка ў найнижшым спакульным аб’екте, а чыста локальны стан UI залічваеце локальным.
- Калі компонент стае важкім для змены, перад тым, як дадаць ўтварэнне новага канстанты для змены стану, запытайцеся, які рэальны факт представляе кожная зменная стану. Стан, які лёгкае ў падтрымцы сінхроннасці, — гэта стан, які вы ніколі не зберагалі.
Спаднёе чытанне
- React Query і Redux: Наватарэнне пад стан сервера ў вялікіх дапрацоўках — Дазвольце дазнацца, чаму дапрацоўка чата для прымення выкорыставала TanStack Query заместо Redux для керування дадзеннямі сервера, і дзе Redux яшчэ мае сваё месца ў савременной архітэктуре React.
- Наватарэнне пад станом у React: Дзе насправды должны знаходзіцца вашы дадзеныя — У этай статыце пояснюецца, як зменшыць колькасць бягоў у React, пераносячы стан у URL, DOM або выведзеныя значэння заместа частага выкарыстоўвання useState.