Хичээл: React-н танилцуулга
These docs are old and won’t be updated. Go to react.dev for the new React docs.
The updated Tutorial teaches modern React and includes live examples.
Энэхүү зааварчилгаа нь таныг өмнө нь React-ийн мэдлэггүй гэж тооцсон болно.
Зааварчилгааг эхлүүлэхийн өмнө
Энэхүү зааварчилгаагаар бид нэг жижигхэн тоглоом хийх болно. Та тоглоом хийхгээгүй учраас алгасах гэж байж магадгүй юм — гэхдээ үүнээс өмнө түр азнаарай. Энэхүү зааварчилгаанаас сурах арга ажиллагаа нь ямар ч React апп хийхэд суурь болохоос гадна сайн сурвал React-ийн талаар гүнзгий ойлголттой болно.
Зөвлөмж
Энэхүү зааварчилгаа нь хийнгээ суралцах-г эрхэмлэдэг хүмүүст зориулагдсан. Хэрэв та зарчмыг нь сууриас нь эхлэн суралцахыг хүсвэл манай алхам-алхмаар заасан зааврыг уншаарай. Та энэхүү зааварчилгаа нь нөгөө заавартай харилцан бие биенээ нөхөж бүхэл цогц болохыг ойлгоно.
Энэхүү зааварчилгаа нь хэдэн хэсэгт хуваагдана:
- Зааварчилгаанд бэлдэх нь хэсгээс зааварчилгааг эхлүүлнэ
- Ерөнхий мэдээлэл хэсгээс React-ийн component, props болон state зэрэг суурь ойлголт-уудыг сурах болно.
- Тоглоомоо хөгжүүлж дуусгах нь хэсгээс React хөгжүүлэлтийн үеийн хамгийн чухал арга аргачлалыг сурах болно.
- Цаг хугацаагаар аялах нь хэсгээс React-ийн онцлог, давуу талыг илүү гүн гүнзгий сурч ойлгох болно.
Энэхүү зааварчилгааг үр дүнтэй ашиглахыг тулд та заавал нэг дор бүх хэсгийг дуусгах алба байхгүй. Нэг эсвэл хоёр хэсэг байсан ч хамаагүй өөрийнхөө хүрч чадах хэсэг хүртэл явахад л болно.
Юу бүтээх вэ?
Энэ зааварчилгаанд React ашиглан хэрхэн tic-tac-toe (икс бөөрөнхий) тоглоомыг бүтээхийг үзүүлэх болно.
Эцсийн бүтээл-с бид юу бүтээх гэж байгааг харж болно. Хэрэв код танд ойлгомжгүй санагдах эсвэл кодын бичлэг нь танил биш харагдвал санаа зовох хэрэггүй. Энэхүү зааварчилгааны зорилго нь танд React болон түүнийг бичиглэлийг ойлгоход туслах билээ.
Энэхүү зааварчилгааг үргэлжлүүлэхээсээ өмнө танд дээрх tic-tac-toe тоглоом уруу орж үзэхийг зөвлөж байна. Нэг анзаарвал зохих тоглоомын боломж нь тоглоомын хөлгийн баруун талд байгаа дугаарласан жагсаалт юм. Энэхүү жагсаалтаас тоглоомын туршид хийгдсэн бүх нүүдлийн түүхийг харж болох бөгөөд тоглох явцад шинэчлэгдэж байна.
Тоглоомтой танилцсан бол түүнийг хааж болно. Учир нь бид илүү энгийн загвараас эхэлнэ. Бидний дараагийн алхам бол таныг тоглоомыг хийж эхлэхэд бэлдэх юм.
Өмнөх шаардлага
Ерөнхийдөө таныг HTML болон Javascript-ийн талаар мэдлэгтэй гэж тооцож байгаа боловч өөр програмчлалын хэлнээс шилжин орж байгаа байсан ч та зааврыг дагаж ажиллах боломжтой байх хэрэгтэй. Мөн таныг функц, объект, массив зэрэг үгүй бол ядаж класс гэх зэрэг програмчлалын ойлголттой гэж тооцсон.
Javascript-ийн мэдлэгээ бататгамаар байвал энэ зааврыг уншихыг зөвлөж байна. Мөн бид Javascript-ийн сүүлийн үеийн хувилбар болох ES6-ийн зарим боломжийг ашиглаж байгааг анзаараарай. Энэхүү зааварт arrow functions, classes, let
, and const
зэрэг бичиглэлийн боломжийг ашиглах болно. Мөн Babel REPL уруу орж ES6 кодыг ямар болгож хөрвүүлэлт хийдгийг харж болох юм.
Зааварчилгаанд бэлдэх нь
Энэхүү зааварчилгааг ажиллах хоёр арга байгаа нь кодоо хөтөч дээрээ бичих эсвэл өөрийн компьютер дээрээ хөгжүүлэлтийн орчин үүсгэх юм.
Бэлтгэл Сонголт 1: Хөтөч дээрээ кодоо бичих
Энэ бол эхлэх хамгийн хурдан арга!
Эхлээд Суурь код -г шинэ тааб дээр нээ. Тэрхүү шинэ тааб дээр хоосон tic-tac-toe тоглоомын хөлөг болон React код харагдах болно. Бид энэ зааварчилгаан дээр тэр React кодыг засаж явна.
Та одоо хоёрдох сонголтыг алгасаад шууд Ерөнхий мэдээлэл хэсгээс React талаар ерөнхий мэдээлэл авах боломжтой.
Бэлтгэл Сонголт 2: Хөгжүүлэлтийн дотоод орчин
Энэ хэсэг нь зааварчилгааг дуусгахад зайлшгүй шаардлагатай биш бөгөөд хүсвэл та хийхгүй ч байж болно!
Заавал биш: Өөрийн дуртай текст засварлагч дээр өөрийн компьютер дээр дагаж хийх заавар.
Энэ аргаар бэлдэх нь зааварчилгааг дуусгахын тулд илүү их ажил хийх шаардлагатай болох боловч өөрийн чинь дуртай эдитор ашиглах боломж олгоно. Доорх хэдэн алхмыг дагаж хийгээрэй:
- Node.js-ийн сүүлийн хувилбарыг суулгасан эсэхээ шалгаж баталгаажуул.
- Create React App суулгах зааврыг дагаж суулгаад шинэ төсөл үүсгээрэй.
npx create-react-app my-app
- Шинэ үүссэн төслийн
src/
хавтас дахь бүх файлыг устга.
Анхаарах:
Бүхэл
src
хавтсыг устгаж болохгүй, зөвхөн түүн доторх эх файлуудыг устгах хэрэгтэй. Бид дараах алхмууд дахь жишээ төслийг гүйцэтгэхдээ энэ эх файлуудыг сольж бичих болно.
cd my-app
cd src
# If you're using a Mac or Linux:
rm -f *
# Or, if you're on Windows:
del *
# Then, switch back to the project folder
cd ..
src/
хавтастindex.css
нэртэй файлыг энд бичсэн CSS кодтойгоор үүсгээрэй.src/
хавтастindex.js
файлыг энд бичсэн JS кодтойгоор үүсгээрэй.src/
хавтас дахьindex.js
файлын дээд талд доорх 3 мөр кодыг бич:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
Одоо хэрэв npm start
гэж төслийн хавтсанд ажиллуулаад хөтөч дээрээ http://localhost:3000
хаягийг нээвэл хоосон tic-tac-toe тоглоомын хөлөг гарч ирэх болно.
Бид танд энэ зааврыг дагаж хийгээд өөрийн эдитор дээр бичиглэлийн тодруулалтыг тохируулахыг зөвлөж байна.
Туслаарай, Би гацчихлаа!
Хэрэв гацчихаад байвал энэхүү олон нийтийн тусламжийн сувгаар орж үзээрэй. Ялангуяа, Reactiflux Chat бол хурдан хугацаанд тусламж авах гайхалтай арга байх болно. Хэрэв чи хариулт авч чадахгүй, ямар нэгэн байдлаар гацсан хэвээр л байвал issue үүсгээрэй, тэгвэл бид танд тусална.
Ерөнхий мэдээлэл
Одоо та бэлтгэлээ хангачихсан бол React-ийн талаар ерөнхий мэдлэг олж авцгаая!
React гэж юу вэ?
React бол user interface хийхэд зориулсан үр дүнтэй, ямар нэгэн журамд баригдаагүй, уян хатан JavaScript сан юм. Энэ нь чамд бүрэн цогц UI-үүдийг “components” гэх бие даасан кодуудаас бүрэлдүүлэх боломжийг олгоно.
React нь хэдэн төрлийн ялгаатай компонентуудтай боловч React.Component
дэд классаас эхэлцгээе:
class ShoppingList extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
// Example usage: <ShoppingList name="Mark" />
Удахгүй дээрх XML төрлийн бичиглэлийг тайлбарлана. Бид нар компонентыг React-д дэлгэц дээр юу гаргахыг хүсэж байгаагаа хэлэхэд ашигладаг. Өгөгдөл өөрчлөгдөх үед React үр дүнтэйгээр компонентыг шинэчилж, дахин үзүүлдэг (render).
Дээр буй ShoppingList бол React компонентын класс, буюу React компонентын төрөл юм. Компонент нь props
(“properties” гэдгийн товчлол) гэсэн параметр аваад render
методоор шаталсан бүтэцтэй үзүүлэх зүйлийг буцаана.
render
метод нь дэлгэц дээр юу гаргахыг хүсэж байгаа зүйлийн чинь тайлбар тодорхойлолт буцаадаг. React тэр тайлбар тодорхойлолтыг аваад үр дүнг харуулна. Тодруулбал render
метод нь юуг үзүүлэхийг л тодорхойлсон React element буцаадаг байх нь. Ихэнх React хөгжүүлэгчид үзүүлэх зүйлийг хялбар бичих боломжтой болгодог “JSX” гэх тусгай бичиглэлийг ашигладаг бөгөөд <div />
бичиглэл нь хөрвүүлэлтийн шатанд React.createElement('div')
уруу хөрвүүлэгдэж байгаа. Тиймээс дээрх жишээ нь доорх кодтой ижил гэсэн үг:
return React.createElement('div', {className: 'shopping-list'},
React.createElement('h1', /* ... h1 children ... */),
React.createElement('ul', /* ... ul children ... */)
);
Дэлгэрэнгүй кодыг ийшээ орж хараарай .
Хэрэв сонирхож байвал createElement()
функцийн тайлбар нь API reference-т дэлгэрэнгүй байгаа боловч энэхүү зааварчилгаанд хэрэглэгдэхгүй. Түүний оронд бид JSX ашиглах болно.
JSX нь Javascript-ийн бүх боломжийг ашиглах боломжтой байдаг тул та ямар ч JavaScript илэрхийллийг JSX-ийн дотор угалзан хаалтад({...}
) бичин ашиглаж болно. React элемент нь хувьсагчид утга оноон эсвэл өөрийнхөө програм дотроо нэгээс нөгөөд дамжуулан ашиглаж болох JavaScript объект юм.
Дээрх ShoppingList
компонент нь зөвхөн <div />
болон <li />
гэх анхнаасаа байдаг DOM компонентуудыг render хийж байна. Гэхдээ та хүссэн React компонентоо үүсгэж, render хийх боломжтой. Жишээ нь бид одоо <ShoppingList />
гэж бичин бүтэн дэлгүүрийн барааны жагсаалт (shopping list)-г оруулж ирэх боломжтой. React компонентууд нь encapsulated бөгөөд бие даан ажилладаг. Энэ нь цогц үйлдэлтэй UI-уудыг энгийн компонентуудаас үүсгэх боломж олгоно.
Суурь кодыг ойлгох нь
Хэрэв энэхүү зааварчилгааг хөтөч дээрээ даган ажиллахаар болсон бол дараах кодыг шинэ тааб дээр нээ: Суурь код. Хэрэв зааварчилгааг өөрийн дотоод орчинд даган ажиллах болсон бол төслийн хавтас дахь src/index.js
-г нээгээрэй. (бэлдцийн үед энэ файлыг үүсгэсэн байх ёстой.).
Энэхүү суурь код нь бидний хийж байгаа зүйлийн эхлэл болох юм. Таныг зөвхөн React сурах болон tic-tac-toe програмчлахад төвлөрөхөд туслах зорилгоор CSS хэвбэржүүлэлтийн кодыг бэлдэж өгсөн.
Кодыг хараад та бидэнд гурван React компоненттой байгааг анзаарна:
- Square (дөрвөлжин)
- Board (хөлөг)
- Game (тоглоом)
Square компонент нь нэг ширхэг <button>
render хийх бөгөөд Board нь 9 дөрвөлжин нүд render хийнэ. Game компонент нь хөлгийг зарим тодорхойгүй утгатай зурж render хийж байгаа бөгөөд тэр утгуудыг бид сүүлд өөрчлөх болно. Одоохондоо ямар ч харилцан үйлчлэлцдэг компонент байхгүй байгаа.
Props-р өгөгдөл дамжуулах
Эхлээд Board компонентоос Square компонент уруу өгөгдөл дамжуулах гэж оролдъё.
Таныг зааварчилгааг ажиллах явцдаа кодуудыг copy/paste хийхгүйгээр өөрөө бичихийг санал болгож байна. Энэ нь таны биед ой санамж үүсгэхээс гадна, илүү ойлгоход тусалдаг.
Board-ийн renderSquare
методын кодыг value
гэх props-г Square уруу дамжуулахаар өөрчилье:
class Board extends React.Component {
renderSquare(i) {
return <Square value={i} />; }
}
Square-ийн render
-д тэрхүү утга (value)-г үзүүлэхийн тулд {/* TODO */}
-г {this.props.value}
-ээр сольж бичье:
class Square extends React.Component {
render() {
return (
<button className="square">
{this.props.value} </button>
);
}
}
Өмнө нь:
Дараа нь: Дөрвөлжин бүрд одоо тоо харагдах ёстой.
Яг одоо код ямар байгааг ийшээ орж хараарай
Баяр хүргэе! Та дөнгөж сая эцэг Board компонентоос хүү Square компонент уруу “prop” дамжуулчихлаа. React програмд эцэг компонентоос хүү компонент уруу props өгч мэдээллийг дамжуулдаг.
Харилцан үйлчлэлцдэг компонент хийх
Одоо Square компонентыг дарах үед түүнийг “X”-ээр бөглөе.
Эхлээд Square компонентын render()
функцийн буцааж байгаа button таагийг доорх байдлаар өөрчилье:
class Square extends React.Component {
render() {
return (
<button className="square" onClick={function() { console.log('click'); }}> {this.props.value}
</button>
);
}
}
Хэрэв одоо Square(дөрвөлжин) дээр дарах юм бол хөтөч дээр чинь alert өгөх болно.
Анхаарах
Бичиглэл бага байлгах болон
this
-ийн ойлгомжгүй байдлаас зайлс хийхийн тулд, event handler-таа энд болон цаашид arrow function бичиглэл-г ашиглалаа:class Square extends React.Component { render() { return ( <button className="square" onClick={() => console.log('click')}> {this.props.value} </button> ); } }
onClick={() => alert('click')}
-аар хэрхэнonClick
prop-т функц дамжуулж байгааг анзаараарай. React энэ функцийг зөвхөн click хийсний дараа дуудна.() =>
гэхээ мартажonClick={alert('click')}
гэж бичих нь түгээмэл алдаа бөгөөд нь энэ нь компонентыг дахин үзүүлэх (render хийх) болгонд alert гаргадаг.
Дараагийн алхамд Square компонент биднийг click хийснийг “санаж” өөрийгөө “X” тэмдэглэгээгээр бөглөх ёстой. Ямарваа юмыг “санахын” тулд компонент state(төлөв байдал) ашигладаг.
React компонентын байгуулагч(constructor)-т this.state
-ийн утгыг оноосноор компонентыг state-тэй болгодог. this.state
нь түүнийг тодорхойлсон React компонент дотор private байх учиртай. Одоо Square-ийн this.state
дэх анхны утгыг тодорхойлоод түүнийг дараа нь Square-д click хийгдэх үед өөрчилье.
Эхлээд state-г үүсгэхийн тулд класст constructor(байгуулагч) нэмж өгье:
class Square extends React.Component {
constructor(props) { super(props); this.state = { value: null, }; }
render() {
return (
<button className="square" onClick={() => console.log('click')}>
{this.props.value}
</button>
);
}
}
Анхаарах
JavaScript класст дэд(хүү) классын байгуулагчийг тодорхойлж байгаа үед заавал
super
функцийг дуудаж байх ёстой. Тиймээс бүхconstructor
-тай React компонентуудын байгуулагч ньsuper(props)
гэж эхэлж байх ёстой болно.
Одоо click хийх үед state-ийн утгыг харуулахын тулд Square-ийн render
методыг өөрчилцгөөе:
<button>
тааг доторхthis.props.value
-гthis.state.value
-ээр соль.onClick={...}
эвент хандлерыгonClick={() => this.setState({value: 'X'})}
-ээр соль.className
болонonClick
props-г тусдаа мөрөнд бичиж уншигдах байдлыг сайжруулъя.
Энэхүү өөрчлөлтийг хийсний дараа Square-ийн render
методоос буцан ирж буй <button>
тааг доорх байдлаар харагдана:
class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null,
};
}
render() {
return (
<button
className="square" onClick={() => this.setState({value: 'X'})} >
{this.state.value} </button>
);
}
}
Square-ийн render
метод дотор onClick
handler -с this.setState
-г дуудсанаар React-д Square-ийн <button>
click хийгдэх болгонд түүнийг дахин render хийхийг даалгаж байгаа юм. Шинэчлэгдсэний дараа Square-ийн this.state.value
нь 'X'
болох бөгөөд тиймээс тоглоомыг хөлөг дээр X
-г үзүүлэх болно. Хэрэв ямар нэгэн Square дээр дарвал X
гарч ирнэ.
Компонентын setState
-г дуудах үед React тэрхүү компонент болон түүний доторх дэд компонентуудыг ч бас шинэчилнэ.
Яг одоо код ямар байгааг ийшээ орж хараарай
Хөгжүүлэгчийн хэрэгсэл
Chrome болон Firefox-т зориулсан хөгжүүлэгчийн хэрэгсэл React Devtools нэмэлтийг суулгаснаар хөтөчийнхөө хөгжүүлэгчийн хэрэгсэл хэсгээс React компонентын бүтцийг харж болдог.
React DevTools-ээр мөн React компонентын props болон state-г харж болно.
React DevTools суулгасны дараа хуудасны дурын элемент дээр right-click хийн “Inspect” дээр даран хөгжүүлэгчийн хэрэгслийг нээх бөгөөд React тааб (“⚛️ Components” and “⚛️ Profiler”) хамгийн баруун талд гарч ирсэн байх болно. “⚛️ Components” ашиглан компонент мод бүтцийг шинжилж болно.
Гэхдээ CodePen дээр үүнийг ажиллуулахын тулд нэмж хэдэн зүйл хийх хэрэгтэй:
- Нэвтэрч орох юм уу бүртгүүлээд и-мэйл хаягаа баталгаажуулах (спам-с сэргийлэхэд хэрэгтэй).
- “Fork” товч дээр дар.
- “Change View” дээр дараад “Debug mode”-г сонго.
- Одоо шинэ тааб нээх үед хөгжүүлэгчийн хэрэгсэл чинь React таабтай болсон байх ёстой.
Тоглоомоо дуусгая
Одоо бид tic-tac-toe тоглоомын суурийг өрчихсөн байгаа. Тоглоомыг дуусгахын тулд бид одоо “X” болон “O”-г сольж нүүдэг мөн ялагчийг тодорхойлдог болгох ёстой.
State-г дээш дамжуулах
Одоогоор Square компонент бүр тусдаа тоглоомын төлөв(state)-г хадгалж байна. Ялагчийг шалгаруулахын тулд 9 square бүрийн утгыг нэг цэгт удирдах хэрэгтэй.
Яахав Board нь Square бүрээс түүний state-ийн утгыг асууж болох юм гэж бодож байна уу. Хэдийгээр React дээр ингэж хийх боломжтой боловч ингэж хийснээр код нь ойлгоход хэцүү, алдаа гарах магадлалтай, засварлахад хүнд болох учраас тэгэхгүй байхыг зөвлөж байна. Түүний оронд хамгийн сайн хандлага бол тоглоомын state-г Square бүрт хадгалахын оронд эцэг Board компонент дээр хадгалах юм. Board компонент нь Square бүрт өмнө нь Square бүрт тоо дамжуулж байсан шиг юуг үзүүлэхийг prop-р дамжуулан хэлж болно.
Олон хүү компонентоос өгөгдөл цуглуулахын тулд эсвэл хоёр хүү компонент хоорондоо харилцахын тулд тэдний эцэг компонентод дундын state зарлах хэрэгтэй. Эцэг компонент нь state-г эргээд хүү компонентууд уруу props-р дамжуулах бөгөөд энэ нь хүү компонентуудыг бусад хүүнүүд болон эцэг компоненттой нэгэн зэрэг ажилладаг болгоно.
State-г дээш эцэг компонент уруу дамжуулах нь React компонентыг дахин шинэчлэх үед түгээмэл хийгддэг үйлдэл бөгөөд үүнийг өөрсдөө одоо хийж үзэцгээе.
Board-д байгуулагч нэмээд Board-ийн state-ийн анхны утгыг 9 нүд бүрд харгалзан 9 null агуулах хүснэгт байдлаар онооё:
class Board extends React.Component {
constructor(props) { super(props); this.state = { squares: Array(9).fill(null), }; }
renderSquare(i) {
return <Square value={i} />;
}
Дараа нь бид хөлгийг харгалзах утгаар бөглөх үед this.state.squares
хүснэгт нь доорх байдлаар болно:
[
'O', null, 'X',
'X', 'X', 'O',
'O', null, null,
]
Board-ийн renderSquare
метод одоо ийм байдлаар харагдана:
renderSquare(i) {
return <Square value={i} />;
}
Эхлээд бид Square бүрт 0-с 8 хүртэл тоо гаргахын тулд Board-с value
prop-г доош дамжуулж өгсөн. Дараагийн алхамд бид Square-г өөрийн state-с хамаарч тоонуудыг “X” тэмдгээр сольдог болгосон. Тиймээс одоо Square нь Board-с дамжуулж өгч байгаа value
prop-ийн утгыг ашиглахгүй байгаа.
Одоо бид prop дамжуулах механизмыг дахин ашиглах болно. Бид Board-г Square бүрт түүнийг одоогийн утгыг('X'
, 'O'
, эсвэл null
) зааж өгдөг болгож өөрчилнө. Өмнө нь Board-ийн байгуулагчид squares
array үүсгэсэн байгаа бөгөөд одоо Board-ийн renderSquare
методыг тэр array-с утга авдаг болгож өөрчилнө:
renderSquare(i) {
return <Square value={this.state.squares[i]} />; }
Яг одоо код ямар байгааг ийшээ орж хараарай
Одоо Square бүр 'X'
, 'O'
, эсвэл хоосон нүдний хувьд null
утгыг value
prop-р авах болно.
Дараа нь бид Square дээр дарахад хийгдэх үйлдлийг солих ёстой. Одоо Board компонент аль нүд бөглөгдөж байхыг шийдэх учраас бидэнд Square нь Board-ийн state-г өөрчлөх арга зам хэрэгтэй болох юм. State нь түүнийг тодорхойлсон компонентын хувьд private тул Board-ийн state-г шууд Square-с өөрчилж чадахгүй.
Түүний оронд бид Board-с Square уруу функц дамжуулж өгөх бөгөөд Square дээр дарахад тэр функцийг Square дуудаж байх болно. Тиймээс Board-ийн renderSquare
методыг доорх байдлаар өөрчилье:
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(i)} />
);
}
Анхаарах
Бид уншихад тохиромжтойг нь бодож буцах элементийг олон мөрт хувааж бичсэн бөгөөд Javascript
return
-ийн ард цэгтэй таслал (;) оруулж улмаар бидний кодыг эвдүүлэхээс сэргийлж хаалт нэмж өглөө.
Одоо Board-с Square уруу хоёр prop дамжуулж өгч байна: value
болон onClick
. onClick
prop нь Square дээр дарахад дуудаж өгөх функц юм. Мөн доорх өөрчлөлтийг Square-т оруулна:
- Square-ийн
render
метод доторхthis.state.value
-гthis.props.value
-ээр солино. - Square’s
render
метод доторхthis.setState()
-гthis.props.onClick()
-ээр солино - Square нь state удирдахаа больсон тул Square-ийн байгуулагч
constructor
функцийг устгана.
Өөрчлөлтийн дараа Square компонент доорх байдлаар харагдана:
class Square extends React.Component { render() { return (
<button
className="square"
onClick={() => this.props.onClick()} >
{this.props.value} </button>
);
}
}
Square дээр дарахад Board-с дамжуулж өгч байгаа onClick
функц дуудагдах бөгөөд хэрхэн энэ үйлдэл явагдахыг доорх байдлаар тайлбарлаж болно:
- Анхнаасаа байдаг DOM компонент
<button>
-ийнonClick
prop нь React-д click event-ийн listener-г бэлдэхийг даалгадаг. - button дарагдах үед React нь Square-ийн
render()
метод дотор тодорхойлогдсонonClick
event handler-г дуудах болно. - Тэр event handler нь
this.props.onClick()
-г дуудах бөгөөд энэ Square-ийнonClick
prop-г Board тодорхойлж өгсөн байгаа. - Board нь Square уруу
onClick={() => this.handleClick(i)}
гэж дамжуулсан учраас Square нь дарагдах үедээthis.handleClick(i)
гэж дуудна. - Бид одоогоор
handleClick()
методыг тодорхойлж өгөөгүй байгаа учраас хэрэв та square дээр дарвал кодонд асуудал үүсэж, “this.handleClick is not a function” (this.handleClick нь функц биш) гэсэн улаан алдааны мэдээлэл гарах болно.
Анхаарах
DOM
<button>
компонент нь анхнаасаа байдаг цаанаасаа тодорхойлж өгсөн компонент учраасonClick
атрибут нь React-ийн хувьд онцгой байдалтай юм. Харин Square зэрэг өөрийн хийсэн компонентын хувьд хэрхэн нэрлэхийг та өөрөө шийднэ. Бид Square-ийнonClick
prop юм уу Board-ийнhandleClick
методыг дурын байдлаар нэрлэж болох бөгөөд тэгсэн ч код яг ижилхэн ажиллах болно. React-ийн хувьд event-г илэрхийлж байгаа prop-гon[Event]
, event-г боловсруулах методыгhandle[Event]
гэж нэрлэх нь уламжлал болсон байдаг.
Бид одоогоор handleClick
-г тодорхойлж өгөөгүй байгаа учраас Square-г дарах үед алдаа гарах болно. Одоо handleClick
-г Board class-т нэмж өгье:
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
};
}
handleClick(i) { const squares = this.state.squares.slice(); squares[i] = 'X'; this.setState({squares: squares}); }
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>
);
}
render() {
const status = 'Next player: X';
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
Яг одоо код ямар байгааг ийшээ орж хараарай
Энэхүү өөрчлөлтийн дараа бид өмнөхийн адил Square дээр дарах боломжтой болно. Гэхдээ state нь тус тусдаа Square нүднүүдэд биш Board-д хадгалагдаж байгаа. Board-ийн state өөрчлөгдөх үед Square компонентууд автоматаар дахин зурагдаж render хийгдэх болно. Бүх нүдний state-г Board компонентод хадгалснаар бид дараа нь ялагчийг тогтоох боломжтой болж байгаа юм.
Square компонент state-г удирдахаа больсон учраас Square нь Board компонентоос утгаа авч, түүнийг дарах үед Board компонент уруу эргээд мэдээлж байна. React-д Square шиг компонентыг удирдагдсан компонент гэж хэлдэг. Board нь түүнийг одоо бүрэн удирдах болно.
Бид handleClick
функц дотор хэрхэн .slice()
функцийг дуудаж squares
array-ийн өмнөх хувилбарыг өөрчлөхгүйгээр шинээр хуулбар үүсгэж байгааг анхаараарай. Бид яагаад ийнхүү squares
array-ийн хуулбарыг үүсгэж байгааг одоо тайлбарлая.
Хувиршгүй байдал(Immutability) яагаад чухал болох нь
Өмнөх жишээнд өөрчлөх ёстой squares
array-ийн хуулбарыг .slice()
оператор ашиглан үүсгэхийг билээ. Одоо бид хувиршгүй байдал гэж болох тухай болон яагаад хувиршгүй байдал чухал талаар ярих болно.
Ерөнхийдөө өгөгдлийг өөрчлөх хоёр хандлага байдаг. Эхнийх нь өгөгдлийн утгыг шууд өөрчлөх замаар өгөгдлийг хувиргах. Нөгөөх нь өгөгдлийг хүсэж байгаа өөрчлөлт хийгдсэн хуулбар өгөгдлөөр солих арга байна.
Хувиргалтаар өгөгдлийг өөрчлөх
var player = {score: 1, name: 'Jeff'};
player.score = 2;
// одоо player нь {score: 2, name: 'Jeff'} болно
Хувиргалтгүй өгөгдлийг өөрчлөх
var player = {score: 1, name: 'Jeff'};
var newPlayer = Object.assign({}, player, {score: 2});
// Одоо player нь өөрчлөгдөөгүй боловч newPlayer нь {score: 2, name: 'Jeff'} болно
// Эсвэл объектыг тархаах бичиглэл ашиглавал доорхоор бичиж болно:
// var newPlayer = {...player, score: 2};
Эцсийн үр дүн ижил боловч шууд хувиргалтгүйгээр (эсвэл гол өгөгдлийг өөрчлөхгүйгээр) доор дурдсан давуу байдлыг олж болж байгаа юм.
Төвөгтэй шаардлагыг хялбарчлах
Хувиршгүй байдал нь төвөгтэй шаардлагыг хийхэд энгийн болгож өгдөг. Энэхүү зааварчилгааны төгсгөлд tic-tac-toe тоглоомын түүхийг харж, өмнөх нүүдэл уруу “ухрах” боломжийг олгох “цаг хугацааны аялал”-н боломжийг хөгжүүлэх болно. Энэхүү үйлдэл нь зөвхөн тоглоом битгий хэл угаасаа л тодорхой үйлдлийг ухраах, урагшлуулах нь хэрэглээний програмын түгээмэл шаардлага билээ. Өгөгдлийг шууд өөрчлөхөөс зайлс хийх нь бидэнд тоглоомын түүхийн өмнөх хувилбаруудыг бүхлээр нь хадгалах мөн тэднийг дараа дахин ашиглах боломж олгоно.
Өөрчлөлтийг илрүүлэх
Хувирахуйц(Mutable) объектын утгуудыг шууд хувиргаад явчихдаг учраас өөрчлөгдсөн эсэхийг илрүүлэх нь хүнд байдаг. Өөрчлөлтийг илрүүлэхийн тулд хувируйц объектийг өмнөх хувилбартай нь жиших хэрэгтэй болохоос гадна бүтэн объектын модоор нэг бүрчлэн орж шалгах хэрэгтэй болдог.
Харин хувиршгүй объектын өөрчлөлтийг илрүүлэх нь хамаагүй хялбар. Хувиршгүй объектын заалт нь өөрчлөгдсөн бол объект өөрчлөгдсөн гэсэн үг.
React хэзээ дахин render хийхийг тодорхойлох
Хувиршгүй байдлын гол давуу тал нь React-д pure components үүсгэхэд тусалдаг. Хувиршгүй өгөгдлийг өөрчлөгдсөн эсэхийг хялбар мэдэж болдог бөгөөд улмаар компонентыг хэзээ дахин зурахыг тодорхойлоход хялбар болгодог.
Гүйцэтгэлийг оновчлох нь хэсгээс shouldComponentUpdate()
-ийн талаар болон хэрхэн pure components хийхийг уншаарай.
Функцэн компонент
Одоо бид Square-г функцэн компонент болгон засах болно.
React-д функцэн компонент нь өөрийн state-гүй зөвхөн render
функцийг агуулдаг компонент бичих энгийн арга юм. React.Component
-с удамшсан класс тодорхойлохын оронд зөвхөн props
аваад юуг render хийхийг буцаадаг функц бичиж болдог. Функцэн компонент нь класс бичихээс ажил багатай бөгөөд олон төрлийн компонент энэ аргаар бичигдэж болдог.
Square классыг доорх функцээр сольё:
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
this.props
-г props
болгож өөрчилсөн болно.
Яг одоо код ямар байгааг ийшээ орж хараарай
Анхаарах
Square-г функцэн компонент болгон өөрчлөх үед
onClick={() => this.props.onClick()}
-г илүү богинохонonClick={props.onClick}
болгон мөн өөрчиллөө. (хоёр талд нь хаалтгүй болсон байгааг назгайраарай).
Ээлжлэх нь
Одоо бид тоглоом дээрээ “O” тэмдэглэгдэхгүй байгаа мэдээжийн алдааг засах болно.
Бид эхний нүүдлийг “X” гэж тохируулах бөгөөд үүнийг Board-ийн байгуулагчид state-ийн анхны утга оноохдоо зааж өгөх болно:
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
xIsNext: true, };
}
Тоглогч нүүх бүрд xIsNext
(boolean) утга нь солигдож дараагийн удаа аль тоглогч нүүхийг тодорхойлох бөгөөд тоглоомын state-д хадгалагдана. Board-ийн handleClick
функцийг засаж xIsNext
-ийн утгыг сольдог өөрчлөлтийг хийе:
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = this.state.xIsNext ? 'X' : 'O'; this.setState({
squares: squares,
xIsNext: !this.state.xIsNext, });
}
Одоо энэ өөрчлөлтөөр “X” болон “O”-ийн утга ээлжлэх юм. Оролдоод ч үзэж болно!
Одоо мөн Board-ийн render
доторх “status” текстийг сольсноор дараагийн удаа аль тоглогч нүүхийг дэлгэц дээр харуулна:
render() {
const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
return (
// the rest has not changed
Энэ бүгдийг хийсний дараа Board компонент маань ийм болж хувирна:
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
xIsNext: true, };
}
handleClick(i) {
const squares = this.state.squares.slice(); squares[i] = this.state.xIsNext ? 'X' : 'O'; this.setState({ squares: squares, xIsNext: !this.state.xIsNext, }); }
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>
);
}
render() {
const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
Яг одоо код ямар байгааг ийшээ орж хараарай
Ялагчийг зарлах нь
Одоо бид дараагийн нүүдэл аль тоглогчийнх гэдгийг харуулж байгаа бөгөөд түүнээс гадна тоглоом хожилцсоныг эсвэл нүүх нүүдэл үлдээгүй гэдгийг мөн харуулах учиртай. Доорх туслах функцийг хуулаад файлынхаа хамгийн төгсгөлд буулгаарай:
function calculateWinner(squares) {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a];
}
}
return null;
}
9 нүдтэй array-ийн хувьд энэ функц нь ялагчийг шалгаж аль тохиромжтой 'X'
, 'O'
, эсвэл null
утгыг буцаадаг.
Бид аль нэг тоглогч хожсон эсэхийг шалгахдаа Board-ийн render
функц дотор calculateWinner(squares)
-г дуудах болно. Хэрэв аль нэг нь хожвол бид “Winner: X” эсвэл “Winner: O” гэсэн текст үзүүлэх юм. Board-ийн render
функц доторх status
-ийн зарлалтыг доорх кодоор сольё:
render() {
const winner = calculateWinner(this.state.squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); }
return (
// the rest has not changed
Одоо Board-ийн handleClick
функцийг хэрэв аль нэг тоглогч хожсон юм уу тухайн нүд нь аль хэдийн дарагдсан байвал дахиж дарахад хариу үйлдэл үзүүлэхгүй шууд return хийдэг болгож засъя:
handleClick(i) {
const squares = this.state.squares.slice();
if (calculateWinner(squares) || squares[i]) { return; } squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
Яг одоо код ямар байгааг ийшээ орж хараарай
Баяр хүргэе! Одоо чи ажилладаг tic-tac-toe хийж чадлаа. Мөн чи React-ийн үндсийг сурсан. Тиймээс энэ тоглоомонд чи жинхэнэ ялагч боллоо.
Цаг хугацааны аялал нэмэх нь
Сүүлийн дасгал болгож бүгдээрээ тоглоомын өмнөх нүүдлүүд уруу “цаг хугацааг ухраах” боломжийг бүрдүүлцгээе.
Нүүдлүүдийн түүхийг хадгалах нь
Хэрэв бид squares
array-г хувиргах(mutate) юм бол цаг хугацааны аялал хийх нь үнэхээр хэцүү болох болно.
Гэхдээ бид slice()
функц ашиглан squares
array-ийн хуулбарыг нүүдэл бүрийн дараа үүсгэж байгаа бөгөөд хувиршгүй гэж тооцсон байгаа. Энэ нь бидэнд squares
array-ийн өмнөх хувилбар бүрийг хадгалах, өмнө болсон нүүдэл бүрийн хооронд явах боломжийг олгоно.
Хуучин squares
array-г өөр history
гэсэн array-д хадгалъя. history
нь эхний нүүдлээс эцсийн нүүдэл хүртэлх Board-ийн бүх state-г хадгалах бөгөөд доорх байдлаар харагдана:
history = [
// Before first move
{
squares: [
null, null, null,
null, null, null,
null, null, null,
]
},
// After first move
{
squares: [
null, null, null,
null, 'X', null,
null, null, null,
]
},
// After second move
{
squares: [
null, null, null,
null, 'X', null,
null, null, 'O',
]
},
// ...
]
Одоо бид аль компонент history
state-г өөртөө агуулахыг шийдэх хэрэгтэй.
Дахиад State-г дээш дамжуулах нь
Бид нар дээд талын Game компонент өнгөрсөн нүүдлийн жагсаалтыг харуулахыг хүсэж байгаа. Тэгэхийн тулд энэ компонент history
уруу хандах хэрэгтэй бөгөөд тиймээс history
state-г дээд талын Game компонентод байрлуулъя.
history
state-г Game компонентод байрлуулах нь биднийг squares
state-г түүнийг хүү Board компонентоос устгах нөхцөл бүрдүүлнэ. Яг өмнө нь Square компонентоос Board компонент уруу “state дээш дамжуулж ” байсан шиг бид одоо Board компонентоос дээд талын Game компонент уруу дээш дамжуулах болно. Ингэснээр Game компонент нь Board-ийн өгөгдлийг бүрэн удирдах бөгөөд history
-с өмнөх нүүдлийг авч Board-р үзүүлэх боломжтой болгох юм.
Эхлээд Game компонентын state-г түүний байгуулагч дотор үүсгэе:
class Game extends React.Component {
constructor(props) { super(props); this.state = { history: [{ squares: Array(9).fill(null), }], xIsNext: true, }; }
render() {
return (
<div className="game">
<div className="game-board">
<Board />
</div>
<div className="game-info">
<div>{/* status */}</div>
<ol>{/* TODO */}</ol>
</div>
</div>
);
}
}
Дараа нь Board компонентыг squares
болон onClick
props-г Game компонентоос авдаг болгоё. Board компонентод бүх Square-т зориулж ганц л click handler байгаа учраас бид аль Square дарагдсаныг мэдэгдэхийн тулд Square тус бүрийн байрлалыг onClick
handler уруу дамжуулах ёстой. Тиймд Board компонентод дараах өөрчлөлтийг хийх хэрэгтэй болно:
- Board доторх
constructor
-г устгана. - Board-ийн
renderSquare
доторхthis.state.squares[i]
-гthis.props.squares[i]
-ээр солино. - Board-ийн
renderSquare
доторхthis.handleClick(i)
-гthis.props.onClick(i)
-ээр солино.
Board компонент одоо доорх байдалтай болно:
class Board extends React.Component {
handleClick(i) {
const squares = this.state.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
renderSquare(i) {
return (
<Square
value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />
);
}
render() {
const winner = calculateWinner(this.state.squares);
let status;
if (winner) {
status = 'Winner: ' + winner;
} else {
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
Тоглоомын төлөвийг тодорхойлох улмаар үзүүлэхэд хамгийн сүүлийн history бүртгэлийг ашиглах гэж Game компонентын render
функцийг доорх байдлаар засъя:
render() {
const history = this.state.history; const current = history[history.length - 1]; const winner = calculateWinner(current.squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); }
return (
<div className="game">
<div className="game-board">
<Board squares={current.squares} onClick={(i) => this.handleClick(i)} /> </div>
<div className="game-info">
<div>{status}</div> <ol>{/* TODO */}</ol>
</div>
</div>
);
}
Game компонент нь одоо тоглоомын төлөвийг үзүүлж байгаа учир бид Board компонентын render
методоос харгалзах кодыг устгаж болно. Тэгсний дараа Board-ийн render
функц ийм байдалтай болно:
render() { return ( <div> <div className="board-row"> {this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
Эцэст нь handleClick
методыг Board компонентоос Game компонент уруу зөөх хэрэгтэй. Game компонентын state нь өөр бүтэцтэй тул бид handleClick
-г бага зэрэг засах хэрэгтэй болно. Game-ийн handleClick
метод дотор бид шинэ history бүртгэлийг history
уруу залгаж(concat) өгье.
handleClick(i) {
const history = this.state.history; const current = history[history.length - 1]; const squares = current.squares.slice(); if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
history: history.concat([{ squares: squares, }]), xIsNext: !this.state.xIsNext,
});
}
Анхаарах
Бидний илүү танил array
push()
методоос ялгаатай ньconcat()
метод нь үндсэн array-г хувиргадаггүй учраас бид үүнийг ашигласан шүү.
Board компонентод одоо зөвхөн renderSquare
болон render
методууд л хэрэг болно. Тоглоомын төлөв байдал болон handleClick
метод нь Game компонентод байвал илүү тохиромжтой.
Яг одоо код ямар байгааг ийшээ орж хараарай
Хуучин нүүдлүүдийг харуулах нь
tic-tac-toe тоглоомын түүхийг тэмдэглэж авч байгаа учраас бид тоглогчдод түүнийг хуучин нүүдлийн жагсаалт байдлаар харуулах боломжтой.
Бид өмнө нь React элементүүдийг first-class JavaScript objects учраас тэдгээрийг аппликейшн дотроо дамжуулж болно гэдийг мэдэж авсан. React-д олон юм render хийхийн тулд React элементийн array ашиглаж болдог.
JavaScript-т array нь өгөгдлийг нь өөр өгөгдөлд map(буулгалт) хийдэг map()
методтой:
const numbers = [1, 2, 3];
const doubled = numbers.map(x => x * 2); // [2, 4, 6]
map
методыг ашиглаад нүүдлүүдийн түүхийг тус бүр нь дэлгэц дээр button гаргах React элементүүд уруу буулгалт хийж хуучин нүүдэл уруу буцах button-ийн жагсаалт үзүүлье.
Game-ийн render
метод дахьhistory
-г map
хийвэл:
render() {
const history = this.state.history;
const current = history[history.length - 1];
const winner = calculateWinner(current.squares);
const moves = history.map((step, move) => { const desc = move ? 'Go to move #' + move : 'Go to game start'; return ( <li> <button onClick={() => this.jumpTo(move)}>{desc}</button> </li> ); });
let status;
if (winner) {
status = 'Winner: ' + winner;
} else {
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return (
<div className="game">
<div className="game-board">
<Board
squares={current.squares}
onClick={(i) => this.handleClick(i)}
/>
</div>
<div className="game-info">
<div>{status}</div>
<ol>{moves}</ol> </div>
</div>
);
}
Яг одоо код ямар байгааг ийшээ орж хараарай
tic-tac-toe-ийн өмнө гарсан нүүдэл бүрд <button>
элемент агуулах жагсаалтын <li>
элемент үүсгэлээ. Товч бүрт нь this.jumpTo()
методыг дууддаг onClick
handler бичиж өгсөн. Одоогоор jumpTo()
методыг хөгжүүлж өгөөгүй байгаа болно. Одоо тоглоомын туршид болсон бүх нүүдлийн жагсаалт дэлгэц дээр харагдаад харин developer tools console дээр доорх анхааруулга гарсан байх ёстой.
Warning: Each child in an array or iterator should have a unique “key” prop. Check the render method of “Game”.
Анхааруулга: array юм уу iterator-ийн бүх хүү нь давхардахгүй “key” prop-той байх хэрэгтэй. “Game”-ийн render методыг шалгана уу.
Одоо дээрх анхааруулга ямар утгатайг тайлбарлая.
Key-г сонгох нь
Ямар нэгэн жагсаалт(list) render хийхдээ React жагсаалтын нэгж(item) бүрийн тухай зарим мэдээллийг хадгалж авдаг. Тэгээд жагсаалт шинэчлэгдэх үед React юу өөрчлөгдсөн гэдгийг тодорхойлох ёстой. Бид нар жагсаалтын нэгжийг шинээр нэмж, устгаж, дахин эрэмбэлж эсвэл шинэчилж болох л юм.
Гэхдээ доорхыг
<li>Alexa: 7 tasks left</li>
<li>Ben: 5 tasks left</li>
ийм болгож
<li>Ben: 9 tasks left</li>
<li>Claudia: 8 tasks left</li>
<li>Alexa: 5 tasks left</li>
өөрчилж байна гэж бодоод үздээ.
Үүнийг харсан хүн тоог шинэчлэхээс гадна Alexa болон Ben хоёрын байрлалыг солиод Claudia-г дундуур нь хийсэн байна гэж хэлж болох байх. Гэхдээ React нь компьютерын програм учраас биднийг зорилгыг тааж мэдэхгүй, тиймд бид жагсаалтын нэгж бүрийг түүний хүүгээс ялгаруулахын тулд жагсаалтын нэгж бүрд key property-г тодорхойлж өгөх хэрэгтэй. Нэг сонголт нь alexa
, ben
, claudia
string-үүдийг ашиглах юм. Хэрэв өгөгдлөө сангаас татаж харуулж байгаа бол Alexa, Ben, болон Claudia-н өгөгдлийн сан дахь ID-г key-р ашиглаж болно.
<li key={user.id}>{user.name}: {user.taskCount} tasks left</li>
Одоо жагсаалтыг дахин render хийх үед React жагсаалтын нэгж бүрийн key-г авч өмнөх жагсаалтын нэгжээс key нь таарч байгааг хайна. Хэрэв одоогийн жагсаалт нь өмнө нь байгаагүй key-г агуулж байвал React тухайн харгалзах компонентыг үүсгэнэ. Хэрэв одоогийн жагсаалт өмнө байсан key-г агуулаагүй бол харгалзах компонентыг устгах болно. Хэрэв хоёр key давхцаж байгаа бол харгалзах компонентыг байх ёстой байрлалд нь зөөнө. Key нь React-н компонентыг таних тэмдэг бөгөөд тэр нь React-д дахин render хийх хооронд state-г зохицуулах боломж олгодог. Хэрэв компонентын key өөрчлөгдөх юм бол тэр компонент устгаад шинэ state-тай дахин шинээр үүсэх болно.
key
нь React-ийн тусгай, хадгалсан property юм. (мөн ref
адил бөгөөд илүү дээд түвшины хэрэглээнд ашиглагддаг.). Элементийг үүсгэх үед key
property-г ялгаж аваад шууд буцаж байгаа элементэд хадгалдаг. Хэдийгээр key
нь props
-т харьяалагдаж байгаа мэт боловч key
-г this.props.key
-р авч болохгүй. React нь автоматаар аль компонентыг шинэчлэхийг шийдэхэд key
-г ашигладаг. Компонент нь өөрийнхөө key
-г асуух боломжгүй байдаг.
Аливаа өөрчлөгдөх жагсаалт үүсгэхдээ зөв зүйтэй key оноож өгөх нь маш чухал байдгийг байнга санах хэрэгтэй. Хэрэв тохиромжтой key байхгүй байвал өгөгдлөө дахин зохион байгуулж key-тэй болгосон нь дээр.
Хэрэв key оноож өгөөгүй бол React анхааруулга гаргаад array-ийн index-г key-ээр ашигладаг. Харин array-ийн index-г key-аар ашиглах нь жагсаалтын нэгжүүдийн байрлалыг өөрчлөх, дундаас нь устгах, дунд нь шинээр оруулах зэргийг хийх үед асуудал үүсгэдэг. key={i}
гэж дамжуулах нь анхааруулгыг гаргахгүй болгох боловч array-ийн index ашигласантай ижил асуудал үүсгэх бөгөөд тэгэхгүй байхыг зөвлөж байна.
Key нь бүх програмын хувьд давхардахгүй байх албагүй зөвхөн компонент дотор жагсаалтын нэгж компонент нь болон түүний хөрш компонентын хувьд л давхардахгүй байх ёстой.
Цаг хугацааны аялалыг хэрэгжүүлэх нь
tic-tac-toe тоглоомын түүхийн хувьд өнгөрсөн бүх нүүдэл нь түүний нүүдлийн дарааллын дугаар болох давхардаагүй ID-тай. Нүүдлүүдийг хэзээ ч байрлалыг нь өөрчилж, устгаж эсвэл дундуур нь шинийг оруулахгүй учраас нүүдлийн дугаарыг key-ээр ашиглахад асуудал байхгүй.
Game компонентын render
метод дотор method, <li key={move}>
гэж key-г нэмэхэд React-ийн анхааруулга арилах болно:
const moves = history.map((step, move) => {
const desc = move ?
'Go to move #' + move :
'Go to game start';
return (
<li key={move}> <button onClick={() => this.jumpTo(move)}>{desc}</button>
</li>
);
});
Яг одоо код ямар байгааг ийшээ орж хараарай
jumpTo
методыг тодорхойлоогүй байгаа учраас жагсаалтын аль ч хэсэгт дарсан алдаа гарах болно. jumpTo
методыг хөгжүүлэхээс өмнө Game компонентод бид аль нүүдлийг одоо үзэж байгааг тодорхойлох stepNumber
state-г нэмж өгье.
Эхлээд stepNumber: 0
-г Game компонентын байгуулагч constructor
-н дотор анхны state-д нэмж өгье:
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
history: [{
squares: Array(9).fill(null),
}],
stepNumber: 0, xIsNext: true,
};
}
Дараа нь Game компонентод stepNumber
-г шинэчилж байх jumpTo
методыг зарлаж өгнө. Мөн хэрэв stepNumber
-г өөрчилж байгаа тоо нь тэгш бол xIsNext
-г true болгож утга оноох ёстой:
handleClick(i) {
// this method has not changed
}
jumpTo(step) { this.setState({ stepNumber: step, xIsNext: (step % 2) === 0, }); }
render() {
// this method has not changed
}
Одоо Game-ийн нүднүүд дээр дарахад ажиллах handleClick
методод зарим өөрчлөлт хийе.
Одоо бидний нэмсэн stepNumber
state нь хэрэглэгчид үзүүлж байгаа нүүдлийн утгаас хамаарч өөрчлөгдөнө. Бид дараагийн нүүдлийг хийх үед stepNumber
-ийн утгыг this.setState
-ийн аргумент болгож stepNumber: history.length
гэх байдлаар шинэчлэх хэрэгтэй. Энэ нь шинэ нүүдэл хийгдсэний дараа бидэнд ижил нүүдэл харагдуулаад байхгүй гэсэн баталгааг өгч байгаа юм.
Бид мөн this.state.history
-г this.state.history.slice(0, this.state.stepNumber + 1)
-ээр солих болно. Энэ нь хэрэв бид өнгөрсөн нүүдэл уруу очоод тэр цэгээс эхлэн дахин шинээр нүүдэл хийвэл одоо хэрэггүй болсон дараагийн нүүдлүүдийг байхгүй болгох юм.
handleClick(i) {
const history = this.state.history.slice(0, this.state.stepNumber + 1); const current = history[history.length - 1];
const squares = current.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
history: history.concat([{
squares: squares
}]),
stepNumber: history.length, xIsNext: !this.state.xIsNext,
});
}
Эцэст нь Game компонентын render
методыг байнга сүүлийн нүүдлийг render хийхийг болиулж stepNumber
-ийн дагуу сонгогдсон нүүдлийг render хийдэг болгож өөрчилнө:
render() {
const history = this.state.history;
const current = history[this.state.stepNumber]; const winner = calculateWinner(current.squares);
// the rest has not changed
Одоо хэрэв тоглоомын өмнөх түүх дээр дарах юм бол tic-tac-toe-ийн хөлөг нь тухайн нүүдэл хийгдсэний дараа хөлөг ямар харагдаж байсан тийм харагдахаар даруй өөрчлөгдөнө.
Яг одоо код ямар байгааг ийшээ орж хараарай
Дүгнэж үзье
Баяр хүргэе! Та доорх үйлдлийг хийдэг tic-tac-toe тоглоом хийж чадлаа:
- tic-tac-toe тоглоом тоглох боломжтой,
- Тоглогч хожилцвол түүнийг тодорхойлдог,
- Тоглоом явагдахад түүний түүхийг хадгалдаг,
- Тоглогч нар тоглоомын түүхийг харж, тоглоомын хөлөгийн өмнөх хувилбаруудыг үзэж болдог.
Одоо таныг React хэрхэн ажилладаг талаар сайн ойлголттой болсон гэж итгэж байна.
Эцсийн үр дүнг дараах хуудаснаас үзээрэй: Эцсийн үр дүн.
Хэрэв танд шинээр сурсан React чадвараа дадлагажуулах цаг, сонирхол байвал tic-tac-toe тоглоомондоо хийж болох дараах сайжруулалтын санааг хэрэгжүүлээд үзээрэй. Эдгээрийг хүндрэлийнх түвшингээр нь жагсаасан болно:
- Нүүдлийн түүхийн жагсаалтад (багана, мөр) хэлбэрээр нүүдэл бүрийн байрлалыг харуулах.
- Нүүдлийн жагсаалтад одоо сонгогдсон хэсгийг тодруулах.
- Board-ийн нүднүүдийг нэг бүрчлэн кодчилохын оронд хоёр давхар давталтаар хэвлэх.
- Нүүдлийн жагсаалтыг өсөх эсвэл буурах эрэмбээр жагсаадаг товчлуур нэмэх.
- Хэрэв хэн нэгэн хожвол хожлыг илтгэсэн 3 нүдийг тодруулдаг болгох.
- Хэрэв аль нь ч хожоогүй бол гарч ирсэн үр дүнг гаргасан мэдээлэл үзүүлэх.
Энэхүү зааварчилгааны турш бид элемент, компонент, props болон state гэсэн React-ийн ухагдахуунуудтай ашиглалаа. Эдгээр сэдвүүдийн талаар илүү дэлгэрэнгүй тайлбарыг гарын авлагын бусад хэсгээс үзээрэй. Компонент тодорхойлох талаар илүү сурахыг хүсвэл React.Component
API reference-г үзээрэй.