React մտածելակերպ

React-ը, մեր կարծիքով, JavaScript-ով արագ և մեծ վեբ հավելվածներ կառուցելու լավագույն միջոցն է։ Այն շատ լավ է ընդլայնվել մեզ համար Facebook-ում և Instagram-ում։

React-ի հիանալի մասերից մեկն այն է, թե ինչպես է այն ուղղորդում մտածել հավելվածների մասին դրանց կառուցելիս։ Այս բաժնում մենք կանցնենք React-ով «ապրանքների որոնելի ցուցակ» կառուցելու մտածողության գործընթացով։

Սկսենք մակետից

Պատկերացնենք, թե մենք արդեն ունենք JSON API և մակետ մեր դիզայներից։ Մակետը հետևյալ տեսքն ունի.

Մակետը

Մեր JSON API-ը վերադարձնում է հետևյալ տեսքի տվյալներ.

[
  {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
  {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
  {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
  {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
  {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
  {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
];

Քայլ 1. տրոհել UI-ը կոմպոնենտների հիերարխիայի

Առաջին բանը, որ կցանկանաք անել, մակետում յուրաքանչյուր կոմպոնենտի (նաև ենթակոմպոնենտի) շուրջ սահմաններ գծելն ու նրանց անուններ տալն է։ Եթե դուք աշխատում եք դիզայների հետ, ապա նրանք միգուցե արդեն արել են դա. խոսեք նրանց հետ։ Նրանց Photoshop-ի layer-ի անունները հնարավոր է համապատասխանեն ձեր React կոմպոնենտների անունների հետ։

Բայց ինչպե՞ս իմանալ, թե կոնկրետ ինչն է կոմպոնենտ։ Оգտագործեք նույն գործելակերպը, ինչ օգտագործում եք որոշելու համար, թե արդյոք պետք է ստեղծեք ֆունկցիա կամ օբյեկտ։ Նմանատիպ գործելակերպ է միակ պատասխանատվության սկզբունքըeng. այն է` կոմպոնենտը պետք է իրականում անի միայն մեկ գործողություն։ Եթե շատ է մեծանում, պետք է բաժանել ավելի փոքր ենթակոմպոնենտների։

Քանի որ օգտագործողի համար հաճախ պատկերում եք JSON տվյալների մոդել, ապա կընդունեք, որ եթե ձեր մոդելը կառուցված է ճիշտ, ապա ձեր UI-ը նույնպես կլինի ճիշտ (հետևաբար նաև ձեր կոմպոնենտի կառուցվածքը)։ Դրա պատճառն այն է, որ UI-ն ու տվյալների մոդելները հակված են պահել նույն ինֆորմացիոն ճարտարապետությունը, ինչը նշանակում է, որ ձեր UI-ը կոմպոնենտերի տրոհելու աշխատանքը հաճախ տրիվյալ է։ Ուղղակի բաժանեք կոմպոնենտները այնպես, որ յուրաքանչյուրը ներկայացնի ճիշտ մեկ կտոր ձեր տվյալների մոդելից։

Կոմպոնենտի դիագրամ

Այստեղ դուք կտեսնեք, որ մեր հավելվածում ունենք հինգ կոմպոնենտ։ Մենք սկզբնարժեքավորել ենք յուրաքանչյուր կոմպոնենտի ներկայացրած տվյալները։

  1. FilterableProductTable (նարնջագույն): ամբողջությամբ պարունակում է օրինակը
  2. SearchBar (կապույտ): ստանում է օգտագործողի բոլոր մուտքագրումները
  3. ProductTable (կանաչ): պատկերում և ֆիլտրում է տվյալների բազմությունը` հիմնվելով օգտագործողի մուտքագրումների վրա
  4. ProductCategoryRow (երկնագույն): յուրաքանչյուր կատեգորիայի համար պատկերում է գլխամասային վերնագիր
  5. ProductRow (կարմիր): յուրաքանչյուր ապրանքի համար պատկերում է տող

Երբ դուք նայեք ProductTable-ին, կտեսնեք, որ նրա գլխամասային վերնագիրը (որը պարունակում է «Name» և «Price» պիտակները) ինքն իրենով առանձին կոմպոնենտ չէ։ Սա նախասիրության հարց է, սակայն կա արգումենտ այն պատրաստելու մյուս եղանակով։ Այս օրինակի պարագայում մենք թողեցինք այն որպես ProductTable-ի մաս, որովհետև այն տվյալների բազմության արտապատկերման մասն է կազմում, որն էլ ProductTable-ի պատասխանատվության տակ է։ Ինչև, եթե այս գլխամասային վերնագիրը բարդանա (օրինակ, եթե մեզ պետք լիներ ավելացնել հնարավորություն դասակարգման համար), ապա, իհարկե, իմաստ կունենար սարքել այն առանձին կոմպոնենտ` ProductTableHeader։

Հիմա, երբ տարբերակել ենք մակետի կոմպոնենտները, եկեք դասավորենք նրանց հիերարխայի մեջ։ Կոմպոնենտները, որոնք մակետում գտնվում են ուրիշ կոմպոնենտների մեջ, պետք է հանդիսանան զավակ կոմպոնենտ հիերարխայում.

  • FilterableProductTable

    • SearchBar
    • ProductTable

      • ProductCategoryRow
      • ProductRow

Քայլ 2. կառուցել ստատիկ տարբերակ React-ում

Նայիր Pen-ը React մտածելակերպ. քայլ 2 CodePen-ում։

Հիմա, երբ արդեն ունեք կոմպոնենտների հիերարխիան, ժամանակն է իրականացնել ձեր հավելվածը։ Հեշտագույն ճանապարհն է կառուցել տարբերակ, որը կստանա ձեր տվյալների մոդելը և կարտապատկերի UI-ը, սակայն առանց ինտերակտիվության։ Շատ կարևոր է առանձնացնել այդ պրոցեսները, որովհետև ստատիկ տարբերակի կառուցումը պահանջում է երկար կոդ գրել և քիչ մտածել, իսկ ինտերակտիվության ավելացումը պահանջում է շատ մտածել և քիչ կոդ գրել։ Մենք կտեսնենք, թե ինչու։

Ձեր տվյալների մոդելն արտապատկերող հավելվածի ստատիկ տարբերակը կառուցելու համար պետք է կառուցել կոմպոնենտներ, որոնք վերա-օգտագործում են ուրիշ կոմպոնենտներ և փոխանցում են տվյալներ` օգտագործելով props։ prop-երը ծնողից զավակ տվյալներ փոխանցելու եղանակ են։ Եթե դուք ծանոթ եք state-ի գաղափարին, ապա բացարձակապես մի օգտագործեք state այն ստատիկ տարբերակը կառուցելու համար։ State-ը միայն ինտերակտիվության համար է, այն է, տվյալներ, որոնք փոխվում են ժամանակի ընթացքում։ Քանի որ սա հավելվածի ստատիկ տարբերակն է, դուք դրա կարիքը չունեք։

Դուք կարող եք կառուցումը սկսել վերևից-ներքև կամ ներքևից-վերև։ Այսինքն` կամ սկսել կոմպոնենտների կառուցումը հիերարխիայում ավելի բարձրից (օրինակ, սկսենք FilterableProductTable-ից) կամ ավելի ներքևից (ProductRow)։ Ավելի պարզ օրինակներում սովորաբար ավելի հեշտ է գնալ վերևից-ներքև ճանապարհով, իսկ ավելի մեծ պրոյեկներում ավելի հեշտ է գնալ ներքևից-վերև ճանապարհով և գրել թեստեր կառուցման ընթացքում։

Այս քայլի վերջում դուք կունենաք վերա-օգտագործվող կոմպոնենտների գրադարան, որն արտապատկերում է ձեր տվյալների մոդելը։ Կոմպոնենտները կունենան միայն render() մեթոդ, քանի որ սա ձեր հավելվածի ստատիկ տարբերակն է։ Հիերարխիայի վերևում գտնվող կոմպոնենտը (FilterableProductTable) կստանա ձեր տվյալների մոդելը որպես prop։ Եթե դուք կատարեք փոփոխություն բազային տվյալների մոդելում և կրկին կանչեք ReactDOM.render()-ը, ապա ձեր UI-ը կթարմացվի։ Դուք կարող եք նկատել, թե ինչպես է ձեր UI-ը թարմացվել։ React-ի միակողմանի տվյալների հոսքը («one-way data flow», հայտնի ինչպես նաև «one-way binding») պահում է ամեն ինչ մոդուլյար և արագագործ է։

Անցեք React-ի փաստաթղթավորումով, եթե կան հարցեր այս քայլի հետ կապված։

Փոքրիկ շեղում. props-ի և state-ի տարբերությունը

React-ում կան երկու տեսակի տվյալների «մոդելներ». props և state։ Կարևոր է հասկանալ տարբերությունը այս երկուսի միջև. անցեք React-ի պաշտոնական փաստաթղթավորումով, եթե վստահ չեք, թե որն է տարբերությունը։

Քայլ 3. սահմանել UI-ի state-ի մինիմալ (բայց ամբողջական) ներկայացումը

Որպեսզի դարձնեք ձեր UI-ը ինտերակտիվ, դուք պետք է իվիճակի լինեք կատարել փոփոխություններ ձեր բազային տվյալների մոդելում։ React-ը հասնում է սրան state-ի օգնությամբ։

Ձեր հավելվածը ճիշտ կառուցելու համար, նախ պետք է մտածեք այն մինիմալ փոփոխելի state-ի մասին, որի կարիքն ունի ձեր հավելվածը։ Կարևոր գաղափարն այստեղ` DRY: Don’t Repeat Yourselfeng-ն է։ Որոշեք ձեր հավելվածին անհրաժեշտ state-ի բացարձակ մինիմալ ներկայացումը և հաշվեք մնացած ամեն ինչն ըստ պահանջի։ Օրինակ, եթե դուք կառուցում եք TODO ցուցակ, պահեք TODO էլեմենտների զանգված. մի պահեք առանձին state-ի փոփոխական քանակի համար։ Փոխարենը, երբ ցանկանաք արտապատկերել TODO-ների քանակը, վերցրեք TODO էլեմենտների զանգվածի երկարությունը։

Եկեք դիտարկենք մեր հավելվածի տվյալների առանձին կտորները։ Մենք ունենք.

  • Ապրանքների նախնական ցուցակ
  • Օգտագործողի մուտքագրած որոնման տեքստ
  • checkbox-ի արժեք
  • Ապրանքների ֆիլտրված ցուցակ

Եկեք անցնենք յուրաքանչյուրով վրայով և հասկանանք, թե նրանցից որ մեկն է state-ի մաս։ Տվյալների յուրաքանչյուր կտորի մասին տվեք երեք հարց.

  1. Սա փոխանցվա՞ծ է ծնողից որպես prop։ Եթե այո, ապա այն, հավանաբար, state-ի մաս չէ։
  2. Այն ժամանակի ընթացքում մնու՞մ է արդյոք անփոփոխ։ Եթե այո, ապա այն, հավանաբար, state-ի մաս չէ։
  3. Կարո՞ղ եք այն հաշվարկել` հիմնվելով state-ի այլ փոփոխականների կամ prop-երի վրա։ Եթե այո, ապա այն, հավանաբար, state-ի մաս չէ։

Ապրանքների սկզբնական ցուցակը փոխանցված է որպես prop, այսինքն` այն state-ի մաս չէ։ Որոնման տեքստը և checkbox-ի արժեքը կարծես թե state-ի մաս են, քանի որ նրանք փոփոխվում են ժամանակի ընթացքում և չեն կարող հաշվվել ինչ-որ բանից։ ԵՎ վերջապես, ապրանքների ֆիլտրված ցուցակը state-ի մաս չէ, որովհետև այն կարող է հաշվարկվել` համատեղելով ապրանքների սկզբնական ցուցակը և որոնման տեքստն ու checkbox-ի արժեքը։

Այսպիսով, մեր state-ը հետևյալն է.

  • Օգտագործողի մուտքագրած որոնման տեքստը
  • checkbox-ի արժեքը

Քայլ 4. որոշել, թե որտեղ է ձեր state-ը լինելու

Նայիր Pen-ը React մտածելակերպ. քայլ 4 CodePen-ում։

Լավ, մենք որոշել ենք, թե որն է հավելվածի state-ի փոփոխականների մինիմալ բազմությունը։ Հաջորդիվ, մենք պետք է որոշենք, թե որ կոմպոնենտն է փոփոխելու կամ ունենալու այս state-ը։

Հիշեք. React-ն իրենից ներկայացնում է միակողմանի տվյալների հոսք կոմպոնենտների հիերարխիայով։ Կարող է անմիջապես ակնհայտ չլինել, թե որ կոմպոնենտը պետք է state ունենա։ Նորեկների համար սա հաճախ ամենաբարդ հասկացվող մասերից մեկն է. լուծում գտնելու համար հետևեք այս քայլերին.

Ձեր հավելվածի state-ի ցանկացած կտորի համար`

  • Տարբերակիր ցանկացած կոմպոնենտ, որն արտապատկերում է ինչ-որ բան` հիմնվելով այդ state-ի վրա։
  • Գտիր ընդհանուր պատկան կոմպոնենտ (մի կոմպոնենտ, որը հիերարխիայում գտնվում է բարձր այն կոմպոնենտերից, որոնք ունեն տվյալ state-ի կարիքը)։
  • Կամ ընդհանուր պատկան, կամ մեկ ուրիշ կոմպոնենտ` ավելի բարձր հիերարխիայում, պետք է ունենա state-ը։
  • Եթե չեք գտնում կոմպոնենտ, որտեղ տրամաբանական կլինի պահել state-ը, ստեղծեք նոր կոմպոնենտ հենց state-ը պահելու համար և տեղադրեք այն հիերարխիայում պատկան կոմպոնենտից բարձր։

Եկեք կիրառենք այս ռազմավարությունը մեր հավելվածի վրա.

  • ProductTable պետք է ֆիլտրի ապրանքների ցուցակը` հիմնվելով state-ի վրա, իսկ SearchBar-ը պետք է պատկերի որոնման տեքստի և checkbox-ի վիճակը։
  • Ընդհանուր պատկան կոմպոնենտը FilterableProductTable-ն է։
  • Ըստ էության, տրամաբանական է ֆիլտրման տեքստը և checkbox-ի արժեքը պահել FilterableProductTable-ում։

Շատ բարի, այսպիսով մենք որոշել ենք, որ մեր state-ը լինի FilterableProductTable-ում։ Նախ, FilterableProductTableconstructor-ում ավելացրեք this.state = {filterText: '', inStockOnly: false}` ձեր հավելավածի սկզբնական վիճակը արտացոլելու համար։ Այնուհետև փոխանցեք filterText-ը և inStockOnlyProductTable-ին ու SearchBar-ին որպես prop։ ԵՎ վերջապես, օգտագործեք այդ prop-երը ProductTable-ի տողերը ֆիլտրելու ու SearchBar-ի դաշտերը արժեքներով լրացնելու համար։

Դուք կնկատեք փոփոխություն ձեր հավելվածի պահվածքի մեջ. filterText-ին տվեք "ball" արժեքը և թարմացրեք (refresh) հավելվածը։ Դուք կտեսնեք, որ ապրանքների ցուցակը թարմացել է ճիշտ կերպով։

Քայլ 5. ավելացնել տվյալների հակառակ ուղղության հոսք

Նայիր Pen-ը React մտածելակերպ. քայլ 5 CodePen-ում։

Մինչ այս, մենք կառուցել ենք հավելված, որն արտապատկերում է կախված հիերարխիայով դեպի ներքև հոսող props-ից ու state-ից։ Հիմա ժամանակն է ապահովել տվյալների հոսք մյուս ուղղությամբ. հիերարխիայի խորքում գտնվող SearchBar-ի կոմպոնենտները կարիք ունեն FilterableProductTable-ի state-ը թարմացնելու։

React-ը դարձնում է այս տվյալների հոսքը բացահայտ, ձեզ օգնելու համար հասկանալ, թե ինչպես է աշխատում ձեր հավելվածը։ Բայց մեզ պետք կգա մի փոքր ավել կոդ գրել ավանդական երկկողմանի տվյալների կապվածությունը ստանալու համար։

Եթե դուք փորձեք գրել կամ սեղմել checkbox-ը օրինակի ընթացիկ տարբերակում, ապա կտեսնեք, որ React-ն անտեսում է ձեր մուտքագրումները։ Սա կանխամտածված է, քանի որ մենք input-ում value prop-ին տվել էինք FilterableProductTable-ից փոխանցված state-ի արժեքը։

Եկեք մտածենք, թե ինչ ենք ուզում, որ տեղի ունենա։ Մենք ցանկանում ենք լինել վստահ, որ ցանկացած պահի, երբ օգտագործողը փոփոխի form-ը, մենք կթարմացնենք state-ը` օգտագործողի մուտքագրումն արտացոլելու համար։ Քանի որ կոմպոնենտները պետք է թարմացնեն միայն իրենց state-երը, FilterableProductTable-ը կփոխանցի հետկանչի ֆունկցիա SearchBar-ին, որը կկանչի, երբ state-ը պետք լինի թարմացնել։ Մենք կարող ենք օգտագործել onChange իրադարձությունը դրա մասին տեղեկանալու համար։ FilterableProductTable-ի կողմից փոխանցված հետկանչի ֆունկցիաները կկանչեն setState(), և հավելվածը կթարմանա։

Ահա և վերջ

Հուսով ենք, որ սա կտա ձեր գաղափար, թե ինչպես մտածեք React-ով կոմպոնենտներ և հավելվածներ կառուցելու մասին։ Չնայած սա պահանջում է մի փոքր ավելի երկար կոդ գրել, քան դուք արել եք, սակայն միշտ հիշեք, որ կոդը ավելի շատ կարդալու համար է, քան` գրելու. դժվար չէ կարդալ այս մոդուլային, բացահայտ կոդը։ Երբ սկսեք կառուցել կոմպոնենտների մեծ գրադարաններ, դուք իրապես կգնահատեք այս բացահայտությունը և մոդուլայնությունը, իսկ կոդի վերա-օգտագործումը կդարձնի ձեր կոդն ավելի կարճ։ :)