You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/lt/7-bank-project/4-state-management
Lee Stott 2daab5271b
Update Quiz Link
3 weeks ago
..
README.md Update Quiz Link 3 weeks ago
assignment.md 🌐 Update translations via Co-op Translator 3 weeks ago

README.md

Sukurkite bankinę programėlę 4 dalis: Būsenos valdymo koncepcijos

Prieš paskaitą: testas

Prieš paskaitą: testas

Įvadas

Kai internetinė programėlė auga, tampa sudėtinga sekti visus duomenų srautus. Kuris kodas gauna duomenis, kuris puslapis juos naudoja, kur ir kada juos reikia atnaujinti... lengva pasiekti netvarkingą kodą, kurį sunku prižiūrėti. Tai ypač aktualu, kai reikia dalintis duomenimis tarp skirtingų programėlės puslapių, pavyzdžiui, vartotojo duomenimis. Būsenos valdymo koncepcija visada egzistavo įvairiose programose, tačiau internetinėms programėlėms vis augant sudėtingumu, tai tapo svarbiu aspektu, kurį reikia apsvarstyti kuriant.

Šioje paskutinėje dalyje peržiūrėsime sukurtą programėlę, kad iš naujo apgalvotume, kaip valdoma būsena, suteikiant galimybę naršyklės atnaujinimui bet kuriuo metu ir duomenų išsaugojimui tarp vartotojo sesijų.

Reikalavimai

Turite būti baigę duomenų gavimo dalį, susijusią su šia pamoka. Taip pat turite įdiegti Node.js ir paleisti serverio API lokaliai, kad galėtumėte valdyti paskyros duomenis.

Galite patikrinti, ar serveris veikia tinkamai, vykdydami šią komandą terminale:

curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result

Iš naujo apgalvokite būsenos valdymą

Ankstesnėje pamokoje pristatėme pagrindinę būsenos koncepciją mūsų programėlėje su globaliu account kintamuoju, kuris saugo banko duomenis apie šiuo metu prisijungusį vartotoją. Tačiau dabartinis įgyvendinimas turi keletą trūkumų. Pabandykite atnaujinti puslapį, kai esate prietaisų skydelyje. Kas nutinka?

Yra 3 problemos su dabartiniu kodu:

  • Būsena nėra išsaugoma, nes naršyklės atnaujinimas grąžina jus į prisijungimo puslapį.
  • Yra kelios funkcijos, kurios keičia būseną. Kai programėlė auga, tampa sunku sekti pakeitimus ir lengva pamiršti atnaujinti vieną iš jų.
  • Būsena nėra išvaloma, todėl paspaudus Atsijungti paskyros duomenys vis dar lieka, nors esate prisijungimo puslapyje.

Galėtume atnaujinti savo kodą, kad spręstume šias problemas po vieną, tačiau tai sukurtų daugiau kodo dubliavimo ir padarytų programėlę sudėtingesnę bei sunkiau prižiūrimą. Arba galėtume sustoti kelioms minutėms ir iš naujo apgalvoti savo strategiją.

Kokias problemas iš tikrųjų bandome išspręsti?

Būsenos valdymas yra apie geros strategijos radimą sprendžiant šias dvi konkrečias problemas:

  • Kaip išlaikyti duomenų srautus programėlėje suprantamus?
  • Kaip užtikrinti, kad būsenos duomenys visada būtų sinchronizuoti su vartotojo sąsaja (ir atvirkščiai)?

Kai pasirūpinsite šiais aspektais, bet kokios kitos problemos, su kuriomis galite susidurti, gali būti jau išspręstos arba tapti lengviau išsprendžiamos. Yra daug galimų būdų spręsti šias problemas, tačiau mes pasirinkime bendrą sprendimą, kuris apima duomenų ir jų keitimo būdų centralizavimą. Duomenų srautai atrodytų taip:

Schema, rodanti duomenų srautus tarp HTML, vartotojo veiksmų ir būsenos

Čia neaptarsime dalies, kurioje duomenys automatiškai sukelia vaizdo atnaujinimą, nes tai susiję su pažangesnėmis reaktyvaus programavimo koncepcijomis. Tai gera tema gilintis, jei norite išsamiau pasinerti.

Yra daug bibliotekų su skirtingais būsenos valdymo metodais, Redux yra populiarus pasirinkimas. Susipažinkite su naudojamomis koncepcijomis ir modeliais, nes tai dažnai yra geras būdas sužinoti, kokių potencialių problemų galite susidurti didelėse internetinėse programėlėse ir kaip jas galima išspręsti.

Užduotis

Pradėsime nuo šiek tiek refaktoringo. Pakeiskite account deklaraciją:

let account = null;

Į:

let state = {
  account: null
};

Idėja yra centralizuoti visus mūsų programėlės duomenis viename būsenos objekte. Šiuo metu būsenoje turime tik account, todėl tai daug nekeičia, tačiau tai sukuria kelią evoliucijoms.

Taip pat turime atnaujinti funkcijas, kurios ją naudoja. register() ir login() funkcijose pakeiskite account = ... į state.account = ...;

updateDashboard() funkcijos viršuje pridėkite šią eilutę:

const account = state.account;

Šis refaktoringas pats savaime neatnešė daug patobulinimų, tačiau idėja buvo sukurti pagrindą kitoms pakeitimams.

Sekite duomenų pokyčius

Dabar, kai sukūrėme state objektą duomenims saugoti, kitas žingsnis yra centralizuoti atnaujinimus. Tikslas yra palengvinti bet kokių pokyčių sekimą ir kada jie įvyksta.

Kad išvengtume pakeitimų state objekte, taip pat gera praktika laikyti jį nekintamu, tai reiškia, kad jo negalima visiškai modifikuoti. Tai taip pat reiškia, kad norėdami ką nors pakeisti, turite sukurti naują būsenos objektą. Taip sukuriate apsaugą nuo galimų nepageidaujamų šalutinių efektų ir atveriate galimybes naujoms funkcijoms programėlėje, pvz., įgyvendinti atšaukimą/atstatymą, taip pat palengvinate derinimą. Pavyzdžiui, galite registruoti kiekvieną būsenos pakeitimą ir išsaugoti pakeitimų istoriją, kad suprastumėte klaidos šaltinį.

JavaScripte galite naudoti Object.freeze(), kad sukurtumėte nekintamą objekto versiją. Jei bandysite pakeisti nekintamą objektą, bus iškelta išimtis.

Ar žinote skirtumą tarp paviršutiniškai ir giliai nekintamo objekto? Apie tai galite perskaityti čia.

Užduotis

Sukurkime naują updateState() funkciją:

function updateState(property, newData) {
  state = Object.freeze({
    ...state,
    [property]: newData
  });
}

Šioje funkcijoje mes sukuriame naują būsenos objektą ir kopijuojame duomenis iš ankstesnės būsenos naudodami sklaidos (...) operatorių. Tada mes pakeičiame tam tikrą būsenos objekto savybę naujais duomenimis naudodami skliaustų notaciją [property] priskyrimui. Galiausiai mes užrakiname objektą, kad išvengtume pakeitimų, naudodami Object.freeze(). Šiuo metu būsenoje saugome tik account savybę, tačiau su šiuo metodu galite pridėti tiek savybių, kiek reikia.

Taip pat atnaujinsime state inicializaciją, kad įsitikintume, jog pradinė būsena taip pat yra užšaldyta:

let state = Object.freeze({
  account: null
});

Po to atnaujinkite register funkciją, pakeisdami state.account = result; priskyrimą į:

updateState('account', result);

Padarykite tą patį su login funkcija, pakeisdami state.account = data; į:

updateState('account', data);

Dabar pasinaudosime proga išspręsti problemą, kai paskyros duomenys nėra išvalomi, kai vartotojas paspaudžia Atsijungti.

Sukurkite naują funkciją logout():

function logout() {
  updateState('account', null);
  navigate('/login');
}

updateDashboard() funkcijoje pakeiskite nukreipimą return navigate('/login'); į return logout();

Pabandykite užregistruoti naują paskyrą, atsijungti ir vėl prisijungti, kad patikrintumėte, ar viskas vis dar veikia tinkamai.

Patarimas: galite peržiūrėti visus būsenos pakeitimus, pridėdami console.log(state) updateState() apačioje ir atidarę naršyklės kūrimo įrankių konsolę.

Išsaugokite būseną

Dauguma internetinių programėlių turi išsaugoti duomenis, kad galėtų tinkamai veikti. Visi svarbūs duomenys paprastai saugomi duomenų bazėje ir pasiekiami per serverio API, kaip mūsų atveju vartotojo paskyros duomenys. Tačiau kartais taip pat įdomu išsaugoti kai kuriuos duomenis kliento programėlėje, kuri veikia jūsų naršyklėje, siekiant geresnės vartotojo patirties arba pagerinti įkėlimo našumą.

Kai norite išsaugoti duomenis naršyklėje, yra keletas svarbių klausimų, kuriuos turėtumėte sau užduoti:

  • Ar duomenys yra jautrūs? Turėtumėte vengti saugoti bet kokius jautrius duomenis kliente, pvz., vartotojo slaptažodžius.
  • Kiek laiko jums reikia išsaugoti šiuos duomenis? Ar planuojate pasiekti šiuos duomenis tik dabartinei sesijai, ar norite, kad jie būtų saugomi amžinai?

Yra keli būdai saugoti informaciją internetinėje programėlėje, priklausomai nuo to, ką norite pasiekti. Pavyzdžiui, galite naudoti URL, kad saugotumėte paieškos užklausą ir padarytumėte ją dalinamą tarp vartotojų. Taip pat galite naudoti HTTP slapukus, jei duomenys turi būti dalinami su serveriu, pvz., autentifikacijos informacija.

Kita galimybė yra naudoti vieną iš daugelio naršyklės API duomenims saugoti. Dvi iš jų yra ypač įdomios:

  • localStorage: Raktų/Verčių saugykla, leidžianti išsaugoti duomenis, specifinius dabartinei svetainei, tarp skirtingų sesijų. Duomenys, išsaugoti joje, niekada nepasibaigia.
  • sessionStorage: veikia taip pat kaip localStorage, išskyrus tai, kad joje saugomi duomenys ištrinami, kai sesija baigiasi (kai naršyklė uždaroma).

Atkreipkite dėmesį, kad abi šios API leidžia saugoti tik eilutes. Jei norite saugoti sudėtingus objektus, turėsite juos serializuoti į JSON formatą, naudodami JSON.stringify().

Jei norite sukurti internetinę programėlę, kuri neveikia su serveriu, taip pat galima sukurti duomenų bazę kliente, naudojant IndexedDB API. Ši API skirta pažangiems naudojimo atvejams arba jei reikia saugoti didelį kiekį duomenų, nes ją naudoti yra sudėtingiau.

Užduotis

Norime, kad mūsų vartotojai liktų prisijungę, kol jie aiškiai nepaspaudžia Atsijungti mygtuko, todėl naudosime localStorage, kad saugotume paskyros duomenis. Pirmiausia apibrėžkime raktą, kurį naudosime duomenims saugoti.

const storageKey = 'savedAccount';

Tada pridėkite šią eilutę updateState() funkcijos pabaigoje:

localStorage.setItem(storageKey, JSON.stringify(state.account));

Su tuo vartotojo paskyros duomenys bus išsaugoti ir visada atnaujinti, nes anksčiau centralizavome visus būsenos atnaujinimus. Čia pradedame naudotis visais ankstesniais refaktoringais 🙂.

Kadangi duomenys yra išsaugoti, taip pat turime pasirūpinti jų atkūrimu, kai programėlė įkeliama. Kadangi pradėsime turėti daugiau inicializacijos kodo, gali būti gera idėja sukurti naują init funkciją, kuri taip pat apimtų mūsų ankstesnį kodą app.js apačioje:

function init() {
  const savedAccount = localStorage.getItem(storageKey);
  if (savedAccount) {
    updateState('account', JSON.parse(savedAccount));
  }

  // Our previous initialization code
  window.onpopstate = () => updateRoute();
  updateRoute();
}

init();

Čia mes atkuriame išsaugotus duomenis, ir jei jų yra, atnaujiname būseną atitinkamai. Svarbu tai padaryti prieš atnaujinant maršrutą, nes gali būti kodas, kuris remiasi būsena puslapio atnaujinimo metu.

Taip pat galime padaryti Prietaisų skydelio puslapį mūsų programėlės numatytuoju puslapiu, nes dabar išsaugome paskyros duomenis. Jei duomenų nerandama, prietaisų skydelis vis tiek pasirūpina nukreipimu į Prisijungimo puslapį. updateRoute() funkcijoje pakeiskite atsarginį return navigate('/login'); į return navigate('/dashboard');.

Dabar prisijunkite prie programėlės ir pabandykite atnaujinti puslapį. Turėtumėte likti prietaisų skydelyje. Su šiuo atnaujinimu mes išsprendėme visas pradines problemas...

Atnaujinkite duomenis

...Bet mes taip pat galėjome sukurti naują problemą. Oi!

Eikite į prietaisų skydelį naudodami test paskyrą, tada paleiskite šią komandą terminale, kad sukurtumėte naują operaciją:

curl --request POST \
     --header "Content-Type: application/json" \
     --data "{ \"date\": \"2020-07-24\", \"object\": \"Bought book\", \"amount\": -20 }" \
     http://localhost:5000/api/accounts/test/transactions

Dabar pabandykite atnaujinti prietaisų skydelio puslapį naršyklėje. Kas nutinka? Ar matote naują operaciją?

Būsena yra išsaugota neribotai, dėka localStorage, tačiau tai taip pat reiškia, kad ji niekada nėra atnaujinama, kol neatsijungiate nuo programėlės ir vėl neprisijungiate!

Viena galimų strategijų tai išspręsti yra pakartotinai įkelti paskyros duomenis kiekvieną kartą, kai įkeliamas prietaisų skydelis, kad išvengtume pasenusių duomenų.

Užduotis

Sukurkite naują funkciją updateAccountData:

async function updateAccountData() {
  const account = state.account;
  if (!account) {
    return logout();
  }

  const data = await getAccount(account.user);
  if (data.error) {
    return logout();
  }

  updateState('account', data);
}

Šis metodas patikrina, ar šiuo metu esame prisijungę, tada pakartotinai įkelia paskyros duomenis iš serverio.

Sukurkite kitą funkciją, pavadintą refresh:

async function refresh() {
  await updateAccountData();
  updateDashboard();
}

Ši funkcija atnaujina paskyros duomenis, tada pasirūpina prietaisų skydelio puslapio HTML atnaujinimu. Tai yra tai, ką reikia iškviesti, kai įkeliamas prietaisų skydelio maršrutas. Atnaujinkite maršruto Po paskaitos testas

Užduotis

Įgyvendinkite dialogo langą „Pridėti operaciją“

Štai pavyzdys, kaip turėtų atrodyti rezultatas po užduoties atlikimo:

Ekrano nuotrauka, rodanti pavyzdinį dialogo langą „Pridėti operaciją“


Atsakomybės apribojimas:
Šis dokumentas buvo išverstas naudojant AI vertimo paslaugą Co-op Translator. Nors siekiame tikslumo, prašome atkreipti dėmesį, kad automatiniai vertimai gali turėti klaidų ar netikslumų. Originalus dokumentas jo gimtąja kalba turėtų būti laikomas autoritetingu šaltiniu. Kritinei informacijai rekomenduojama profesionali žmogaus vertimo paslauga. Mes neprisiimame atsakomybės už nesusipratimus ar klaidingus interpretavimus, atsiradusius naudojant šį vertimą.