Тази статия е насочена към хора, които вече са имали първия си подход към React и които като начинаещи се съмняват в това как setState
работи и как да го използват правилно. Той също така трябва да помогне на разработчиците от средата до старшите да използват по-чисти и по-абстрахирани начини за задаване на състояние и да накарат функциите от по-висок ред да обработват и абстрактното състояние.
Просто четете и се забавлявайте!
Затова вземете чаша кафе и продължете да четете! ?
Основни концепции на setState ()
React Components ви позволяват да разделите потребителския интерфейс (UI) на независими части за многократна употреба, така че да можете да мислите за всяка част изолирано.
Концептуално компонентите са като JavaScript функции. Те приемат произволни входове (наречени „подпори“) и връщат React елементи, описващи какво трябва да се появи на екрана.
Ако трябва да дадете на потребителя възможност да въведе нещо или по някакъв начин да промените променливите, които компонентът получава като подпори, ще ви трябва setState
.
Независимо дали декларирате компонент като функция или клас, той никога не трябва да променя собствения си реквизит.
Всички React компонентитрябва да действат като чисти функции по отношение на техния реквизит. Това означава функции, които никога не се опитват да променят своите входове и винаги връщат един и същ резултат за едни и същи входове.
Разбира се, потребителските интерфейси на приложенията са динамични и се променят с времето. Ето защо state
е създаден.
State
позволява на компонентите на React да променят изхода си с течение на времето в отговор на потребителски действия, мрежови отговори и всичко останало, без да нарушават това правило.
Компонентите, дефинирани като класове, имат някои допълнителни функции. Local state е функция, достъпна само за клас Components.
setState
е API методът, предоставен с библиотеката, така че потребителят да може да дефинира и манипулира състоянието с течение на времето.
Три правила на палеца при използване на setState ()
Не променяйте директно държавата

Актуализациите на държавата могат да бъдат асинхронни
React може да групира множество setState()
обаждания в една актуализация за изпълнение.
Тъй като this.props
и this.state
може да се актуализира асинхронно, не трябва да разчитате на техните стойности за изчисляване на следващото състояние.

Винаги трябва да се направи този вид манипулация с функционален подход, снабдяващи state
и props
и връщане на новия state
, базиран на първата.
Актуализациите на държавата се обединяват
Когато се обадите setState()
, React обединява обекта, който предоставяте, в текущия state
.
В примера по-долу актуализираме променливата dogNeedsVaccination
независимо от другите state
променливи.
Сливането е плитко, така че this.setState({ dogNeedsVaccination: true })
оставя останалите променливи непокътнати, заменяйки само стойността на dogNeedsVaccination
.

Уважавайте потока от данни и избягвайте да посочвате макс
Данните текат надолу! Нито родителските, нито дъщерните компоненти могат да знаят дали даден компонент е с състояние или без гражданство и не трябва да се интересуват дали той е дефиниран като функция или клас.
Ето защо state
често се нарича местен или капсулиран. Той не е достъпен за друг компонент, освен този, който го притежава и задава.
Когато setState
използвате реквизит и го използвате във вашия компонент, вие нарушавате потока на рендеринг реквизита. Ако по някаква причина пропът, прехвърлен във вашия компонент, се промени в родителския компонент, детето няма да изобрази автоматично магически ?!
Нека проверим пример:

Тук имате Home
компонент, който генерира магическо число на всеки 1000ms и го настройва в свое собствено state
.
След това той изобразява числото и извиква три Child
компонента (братя и сестри), които ще получат магическото число с цел да го покажат, използвайки три различни подхода:
Първи подход
Компонентът ChildOfHome
зачита каскадния поток на React props и, като се има предвид, че целта е само да покаже магическото число, той рендира props
полученото директно.

Втори подход
Компонентът ChildOfHomeBrother
получава props
от своя родител и, извиквайки componentDidMount
, задава магическото число в state
. След това тя показва state.magicNumber
.
Този пример не работи, защото render()
не знае, че a се prop
е променил, така че не задейства повторното изобразяване на компонента. Тъй като компонентът вече не се визуализира, componentDidMount
не се извиква и дисплеят не се актуализира.

Трети подход
Обикновено, когато се опитваме да го накараме да работи, използвайки втория подход, ние мислим, че нещо липсва. Вместо да правим крачка назад, ние продължаваме да добавяме неща към кода, за да работи!
Така че в този трети подход добавихме, за componentDidUpdate
да проверим дали има промяна в props
задействането на повторното изобразяване на компонента. Това е ненужно и ни води до нечист код. Той също така носи със себе си разходи за производителност, които ще бъдат умножени по броя пъти, когато правим това в голямо приложение, където имаме много оковани компоненти и странични ефекти.
Това е грешно, освен ако не е необходимо да позволите на потребителя да промени получената стойност на опората.
Ако не е необходимо да променяте стойността на опората, винаги се опитвайте да поддържате нещата да работят според потока на React (първи подход).
Можете да проверите работеща уеб страница с този пример, който съм ви подготвил в Glitch. Погледнете и се забавлявайте?
Също така проверете кода в Home.js
и HomeCodeCleaned.js
(без HTML неща) в моето репо за тази статия.
Как да настроите State
Така че в този момент мисля, че е време да си изцапаме ръцете!
Нека да си поиграем малко setState
и да подобрим това! Просто следвайте и вземете още една чаша кафе!
Нека създадем малка форма за актуализиране на потребителски данни:

Ето кода за примера по-горе:

Задаваме state
като обект и няма проблем, тъй като текущото ни състояние не зависи от последното ни състояние.
Ами ако създадем още едно поле за формуляр, за да въведем и покажем Фамилия?


Хубаво! Абстрахирахме handleFormChange
метода, за да можем да обработваме всички полета за въвеждане и setState
.
Какво ще стане, ако добавим бутон за превключване, за да маркираме данните като валидни или невалидни и брояч, за да разберем колко промени сме направили в състоянието?


Да! Ние се люлеем! Абстрахирахме много неща!
Хммм ... Да кажем, че не искам квадратче за управление на isValid
променливата, а обикновен бутон за превключване.
Нека също така да отделим манипулатора на брояча от този метод. Работи добре, но в по-сложни ситуации, когато React трябва да промени партиди / групи, не е добра политика да разчитате на this.state.counter
променливата, за да добавите още една. Тази стойност може да се промени, без да сте наясно с нея.
Използваме плитко копие от него в момента, в който се извика операцията, и в този определен момент от времето не знаете дали стойността му е тази, която сте очаквали или не!
Нека да станем малко функционални!


Добре - Загубихме абстракция, защото сме отделили манипулаторите, но това е по основателна причина!
Така че понастоящем поддържаме handleFormChange
предаването на обект към setState
метода на API. Но handleCounter
и handleIsValid
методи вече са функционални и да започнете, като го хванеш на текущото състояние и след това, в зависимост от това състояние, той се променя към следващия.
Това е правилният начин за промяна state
на променливите, които зависят от предишното състояние.
Ами ако искаме да console.log()
заявяваме промени във firstName
и lastName
входните форми всеки път, когато настъпи промяна? Нека опитаме!

Хубаво! Всеки път, когато handleFormChange
възникне (което означава, че се е случило ново натискане на клавиш), logFields()
методът се извиква и регистрира текущото състояние в конзолата!
Нека проверим конзолата на браузъра:

Изчакайте! Какво се случи тук, хора? Дневникът на конзолата е една промяна преди въвеждането на текущата форма! Защо се случва това?
setState е асинхронен !!
Вече знаехме това, но сега го виждаме с очите си! Какво става там? Нека да разгледаме handleFormChange
и logFields
методите по-горе.
Така че handleFormChange
методът получава име и стойност на събитието, а след това прави a setState
от тези данни. След това извиква handleCounter
да актуализира информацията за брояча и накрая извиква logFields
метода. В logFields
метода грабва currentState
и се връща "Едуард", вместо "Едуардо".
Работата е там: setState
е асинхронизиран и не действа в момента. React си върши работата и изпълнява logFields
метода първо, оставяйки setState
за следващия цикъл на събитие.
Но как можем да избегнем този вид ситуация?
Е, setState
API трябва callback
да избегне тази ситуация:

Ако искаме logFields()
да вземе предвид неотдавнашните промени, които направихме в състоянието, трябва да го извикаме в обратното повикване, като това:

Добре, сега работи!
Казваме на React: „Хей React! Внимавайте, че когато извикате logFields
метода, искам да имате state
вече актуализирания добре? Вярвам ти!"
React казва: „Добре Едо! Ще се справя с цялата тази партида неща, които обикновено правя в задния двор с setState
вещта и едва когато приключа с това, ще се позова logFields()
! Готин човек! Отпуснете се!"

И всъщност - работи!
Добре всички! По това време сме се справили с основните клопки на setState
.
Имате ли смелостта да преминете отвъд стената? Вземете една чаша кафе и нека да станем наистина kewl ...
Първи фантазия с setState ()
Сега, когато имаме handleCounter
и handleIsValid
методи, и setState()
изрази с функции, можем да композирате състояние актуализацията с други функции! Аз харесвам композиция! Хайде да се позабавляваме!

Можем да вземем логиката вътре setState
във функция извън компонента на класа. Нека го наречем toggleIsValid
. ☝️

Сега тази функция може да живее извън компонента на класа, навсякъде във вашето приложение.
Ами ако използваме функция от по-висок ред?

Еха! Сега вече не извикваме toggleIsValid
функцията. Извикваме абстрактна функция от по-висок ред, наречена, toggleKey
и предаваме ключ (в този случай низ) в нея.
Как трябва да променим toggleIsValid
функцията сега?

Какво?! Сега имаме функция, наречена, toggleKey
която получава a key
и връща нова функция, която променя състоянието според предоставения ключ.
Това toggleKey
може да бъде в библиотека или в помощен файл. Той може да бъде извикан в много различни контексти, за да промени състоянието на каквото искате в неговата противоположност.
Страхотен!
Нека направим същото с манипулатора на инкрементния брояч:


Да! Работи! Толкова хубаво. Хайде да полудеем сега ...
Снимане на Луната и връщане назад
Ами ако създадем обща makeUpdater
функция, която получава функцията за трансформация, която искате да приложите, взема ключа и връща функцията за състояние, управляваща състоянието с функцията за трансформация и ключа? Малко объркан? Да тръгваме!

Добре, стига ... Нека спрем тук. ?
Можете да проверите целия код, който сме направили в това репо GitHub.
Последно, но не и най-малко
Не забравяйте да избягвате състоянието на максимално използване и да спазвате каскадата на React rendering props.
Не забравяйте, че setState
е асинхронно.
Не забравяйте, че setState
можете да вземете обект или функция
Не забравяйте, че трябва да предадете функция, когато следващото ви състояние зависи от предишното ви състояние.
Библиография
- Документация за реагиране
- Достигнете до технически курсове от Райън Флорънс, които наистина препоръчвам.
Благодаря ти много!