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/sr/7-bank-project/4-state-management
softchris bde9da6dad
🌐 Update translations via Co-op Translator
1 month ago
..
README.md 🌐 Update translations via Co-op Translator 1 month ago
assignment.md 🌐 Update translations via Co-op Translator 1 month ago

README.md

Изградња апликације за банкарство, део 4: Концепти управљања стањем

Квиз пре предавања

Квиз пре предавања

Увод

Управљање стањем је као навигациони систем на свемирској летели Voyager када све функционише како треба, једва примећујете да постоји. Али када нешто крене наопако, то постаје разлика између достизања међузвезданог простора и лутања изгубљеног у космичком вакууму. У веб развоју, стање представља све што ваша апликација треба да памти: статус пријаве корисника, податке из формулара, историју навигације и привремена стања интерфејса.

Како се ваша апликација за банкарство развијала од једноставног формулара за пријаву до сложеније апликације, вероватно сте наишли на неке уобичајене изазове. Освежите страницу и корисници ће бити неочекивано одјављени. Затворите прегледач и сав напредак ће нестати. Решавате проблем и трагате кроз више функција које све модификују исте податке на различите начине.

Ово нису знаци лошег кодирања то су природне потешкоће које се јављају када апликације достигну одређени праг сложености. Сваки програмер се суочава са овим изазовима када њихове апликације прелазе из фазе "доказ концепта" у фазу "спремно за производњу".

У овом предавању ћемо имплементирати централизовани систем за управљање стањем који ће вашу апликацију за банкарство претворити у поуздану, професионалну апликацију. Научићете како да управљате токовима података предвидљиво, да правилно чувате корисничке сесије и да креирате глатко корисничко искуство које модерне веб апликације захтевају.

Предуслови

Пре него што се упустите у концепте управљања стањем, потребно је да правилно подесите своје развојно окружење и поставите темеље апликације за банкарство. Ово предавање се директно надовезује на концепте и код из претходних делова ове серије.

Уверите се да имате следеће компоненте спремне пре него што наставите:

Потребно подешавање:

  • Завршите лекцију о преузимању података - ваша апликација треба успешно да учитава и приказује податке о рачуну
  • Инсталирајте Node.js на вашем систему за покретање backend API-ја
  • Покрените server API локално за обраду операција са подацима о рачуну

Тестирање вашег окружења:

Проверите да ли ваш API сервер ради исправно извршавањем ове команде у терминалу:

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

Шта ова команда ради:

  • Шаље GET захтев вашем локалном API серверу
  • Тестира везу и проверава да ли сервер одговара
  • Враћа информације о верзији API-ја ако све ради исправно

Дијагностика проблема са тренутним стањем

Као Шерлок Холмс који испитује место злочина, морамо разумети шта се тачно дешава у нашој тренутној имплементацији пре него што решимо мистерију нестајућих корисничких сесија.

Хајде да спроведемо једноставан експеримент који открива основне изазове управљања стањем:

🧪 Пробајте овај дијагностички тест:

  1. Пријавите се у вашу апликацију за банкарство и идите на контролну таблу
  2. Освежите страницу прегледача
  3. Посматрајте шта се дешава са вашим статусом пријаве

Ако сте преусмерени назад на екран за пријаву, открили сте класичан проблем са перзистенцијом стања. Ово понашање се дешава јер наша тренутна имплементација чува корисничке податке у JavaScript променљивама које се ресетују при сваком учитавању странице.

Проблеми тренутне имплементације:

Једноставна променљива account из наше претходне лекције ствара три значајна проблема која утичу и на корисничко искуство и на одрживост кода:

Проблем Технички узрок Утицај на корисника
Губитак сесије Освежавање странице брише JavaScript променљиве Корисници морају често да се поново пријављују
Распршене измене Више функција директно модификује стање Дебаговање постаје све теже
Непотпуно чишћење Одјава не брише све референце стања Потенцијални проблеми са безбедношћу и приватношћу

Архитектонски изазов:

Као што је дизајн Титаника са преграђеним одељцима изгледао робусно све док више одељака није истовремено поплављено, решавање ових проблема појединачно неће решити основни архитектонски проблем. Потребно нам је свеобухватно решење за управљање стањем.

💡 Шта заправо покушавамо да постигнемо овде?

Управљање стањем је заправо решавање два основна проблема:

  1. Где су моји подаци?: Праћење информација које имамо и одакле долазе
  2. Да ли су сви на истој страни?: Осигуравање да оно што корисници виде одговара ономе што се заиста дешава

Наш план:

Уместо да се вртимо у круг, направићемо централизовани систем за управљање стањем. Замислите то као да имате једну веома организовану особу која је задужена за све важне ствари:

Шема која приказује токове података између HTML-а, корисничких акција и стања

Разумевање овог тока података:

  • Централизује све стање апликације на једном месту
  • Управља свим променама стања кроз контролисане функције
  • Осигурава да кориснички интерфејс остане синхронизован са тренутним стањем
  • Обезбеђује јасан, предвидљив образац за управљање подацима

💡 Професионални увид: Ова лекција се фокусира на основне концепте. За сложене апликације, библиотеке као што је Redux пружају напредније функције за управљање стањем. Разумевање ових основних принципа помоћи ће вам да савладате било коју библиотеку за управљање стањем.

⚠️ Напредна тема: Нећемо покривати аутоматска ажурирања корисничког интерфејса која се покрећу променама стања, јер то укључује концепте реактивног програмирања. Сматрајте ово одличним следећим кораком у вашем процесу учења!

Задатак: Централизовање структуре стања

Хајде да почнемо са трансформацијом нашег расутог управљања стањем у централизовани систем. Овај први корак поставља темеље за све наредне унапређења.

Корак 1: Креирање централизованог објекта стања

Замените једноставну декларацију account:

let account = null;

Са структурираним објектом стања:

let state = {
  account: null
};

Зашто је ова промена важна:

  • Централизује све податке апликације на једном месту
  • Припрема структуру за додавање више својстава стања касније
  • Креира јасну границу између стања и других променљивих
  • Успоставља образац који се може проширити како ваша апликација расте

Корак 2: Ажурирање образаца приступа стању

Ажурирајте ваше функције да користе нову структуру стања:

У функцијама register() и login(), замените:

account = ...

Са:

state.account = ...

У функцији updateDashboard(), додајте ову линију на врх:

const account = state.account;

Шта ове измене постижу:

  • Одржавају постојећу функционалност уз побољшање структуре
  • Припремају ваш код за сложеније управљање стањем
  • Креирају конзистентне обрасце за приступ подацима стања
  • Постављају темеље за централизована ажурирања стања

💡 Напомена: Ово рефакторисање не решава одмах наше проблеме, али ствара неопходну основу за моћна унапређења која следе!

Имплементација контролисаних ажурирања стања

Са централизованим стањем, следећи корак укључује успостављање контролисаних механизама за модификацију података. Овај приступ осигурава предвидљиве промене стања и олакшава дебаговање.

Основни принцип подсећа на контролу ваздушног саобраћаја: уместо да дозволимо више функција да независно модификују стање, усмерићемо све промене кроз једну, контролисану функцију. Овај образац пружа јасну контролу над тим када и како се подаци мењају.

Управљање неизменљивим стањем:

Третираћемо наш објекат state као неизменљив, што значи да га никада нећемо директно модификовати. Уместо тога, свака промена креира нови објекат стања са ажурираним подацима.

Иако овај приступ може изгледати неефикасно у поређењу са директним модификацијама, он пружа значајне предности за дебаговање, тестирање и одржавање предвидљивости апликације.

Предности управљања неизменљивим стањем:

Предност Опис Утицај
Предвидљивост Промене се дешавају само кроз контролисане функције Лакше за дебаговање и тестирање
Праћење историје Свака промена стања креира нови објекат Омогућава функцију поништавања/поновног извршења
Спречавање нежељених ефеката Нема случајних модификација Спречава мистериозне грешке
Оптимизација перформанси Лако је детектовати када се стање заиста променило Омогућава ефикасна ажурирања корисничког интерфејса

Неизменљивост у JavaScript-у са Object.freeze():

JavaScript пружа Object.freeze() за спречавање модификација објеката:

const immutableState = Object.freeze({ account: userData });
// Any attempt to modify immutableState will throw an error

Објашњење шта се овде дешава:

  • Спречава директна додељивања или брисања својстава
  • Баца изузетке ако се покушају модификације
  • Осигурава да промене стања морају проћи кроз контролисане функције
  • Креира јасан уговор о томе како се стање може ажурирати

💡 Дубински увид: Сазнајте разлику између плитких и дубоких неизменљивих објеката у MDN документацији. Разумевање ове разлике је кључно за сложене структуре стања.

Задатак

Хајде да креирамо нову функцију updateState():

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

У овој функцији, креирамо нови објекат стања и копирамо податке из претходног стања користећи оператор ширења (...). Затим замењујемо одређено својство објекта стања новим подацима користећи нотацију са заградама [property] за додељивање. На крају, закључавамо објекат да спречимо модификације користећи Object.freeze(). Тренутно имамо само својство account у стању, али са овим приступом можете додати онолико својстава колико вам је потребно.

Такође ћемо ажурирати иницијализацију state да бисмо осигурали да је почетно стање такође закључано:

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

Након тога, ажурирајте функцију register заменом state.account = result; са:

updateState('account', result);

Урадите исто са функцијом login, заменом state.account = data; са:

updateState('account', data);

Сада ћемо искористити прилику да решимо проблем са подацима о рачуну који се не бришу када корисник кликне на Logout.

Креирајте нову функцију logout():

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

У функцији updateDashboard(), замените преусмеравање return navigate('/login'); са return logout();.

Пробајте да региструјете нови рачун, одјавите се и поново пријавите да проверите да ли све и даље ради исправно.

Савет: можете погледати све промене стања додавањем console.log(state) на крај функције updateState() и отварањем конзоле у алатима за развој вашег прегледача.

Имплементација перзистенције података

Проблем губитка сесије који смо идентификовали раније захтева решење за перзистенцију које одржава корисничко стање током сесија у прегледачу. Ово трансформише нашу апликацију из привременог искуства у поуздан, професионални алат.

Замислите како атомски часовници одржавају прецизно време чак и током прекида напајања чувајући критично стање у неиспарљивој меморији. Слично томе, веб апликацијама су потребни механизми за перзистенцију како би сачувале битне корисничке податке током сесија у прегледачу и освежавања странице.

Стратешка питања за перзистенцију података:

Пре имплементације перзистенције, размислите о овим критичним факторима:

Питање Контекст апликације за банкарство Утицај одлуке
Да ли су подаци осетљиви? Стање рачуна, историја трансакција Изаберите сигурне методе чувања
**Колико дуго треба да

💡 Напредна опција: За сложене офлајн апликације са великим сетовима података, размислите о коришћењу IndexedDB API. Овај API пружа потпуну базу података на страни клијента, али захтева сложенију имплементацију.

Задатак: Имплементација локалног складиштења (localStorage) за перзистенцију

Хајде да имплементирамо перзистентно складиштење како би корисници остали пријављени све док се експлицитно не одјаве. Користићемо localStorage за чување података о налогу током сесија у претраживачу.

Корак 1: Дефинисање конфигурације складиштења

const storageKey = 'savedAccount';

Шта ова константа обезбеђује:

  • Креира конзистентан идентификатор за наше складиштене податке
  • Спречава грешке у референцама кључева складиштења
  • Олакшава промену кључа складиштења ако је потребно
  • Прати најбоље праксе за одрживи код

Корак 2: Додавање аутоматске перзистенције

Додајте ову линију на крај функције updateState():

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

Објашњење шта се овде дешава:

  • Конвертује објекат налога у JSON стринг за складиштење
  • Чува податке користећи наш конзистентан кључ складиштења
  • Извршава се аутоматски кад год дође до промене стања
  • Осигурава да су складиштени подаци увек синхронизовани са тренутним стањем

💡 Предност архитектуре: Пошто смо централизовали све ажурирања стања кроз updateState(), додавање перзистенције захтевало је само једну линију кода. Ово показује снагу добрих архитектонских одлука!

Корак 3: Враћање стања при учитавању апликације

Креирајте функцију за иницијализацију која враћа сачуване податке:

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

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

init();

Разумевање процеса иницијализације:

  • Преузима све претходно сачуване податке о налогу из localStorage
  • Парсира JSON стринг назад у JavaScript објекат
  • Ажурира стање користећи нашу контролисану функцију ажурирања
  • Враћа корисничку сесију аутоматски при учитавању странице
  • Извршава се пре ажурирања рута како би се осигурало да је стање доступно

Корак 4: Оптимизација подразумеване руте

Ажурирајте подразумевану руту како бисте искористили предности перзистенције:

У updateRoute(), замените:

// Replace: return navigate('/login');
return navigate('/dashboard');

Зашто ова промена има смисла:

  • Ефикасно користи наш нови систем перзистенције
  • Омогућава да контролна табла проверава аутентификацију
  • Преусмерава аутоматски на пријаву ако не постоји сачувана сесија
  • Креира беспрекорно корисничко искуство

Тестирање ваше имплементације:

  1. Пријавите се у вашу апликацију за банкарство
  2. Освежите страницу у претраживачу
  3. Проверите да ли сте остали пријављени и на контролној табли
  4. Затворите и поново отворите претраживач
  5. Поново отворите вашу апликацију и проверите да ли сте још увек пријављени

🎉 Остварено достигнуће: Успешно сте имплементирали управљање перзистентним стањем! Ваша апликација сада функционише као професионална веб апликација.

Балансирање перзистенције и свежине података

Наш систем перзистенције успешно одржава корисничке сесије, али уводи нови изазов: застарелост података. Када више корисника или апликација мења исте серверске податке, локално кеширане информације постају застареле.

Ова ситуација подсећа на викиншке навигаторе који су се ослањали и на сачуване карте звезда и на тренутна посматрања небеских тела. Карте су пружале конзистентност, али навигатори су морали да се ослањају на свежа посматрања како би узели у обзир промене. Слично томе, наша апликација треба и перзистентно корисничко стање и ажурне серверске податке.

🧪 Откривање проблема са свежином података:

  1. Пријавите се на контролну таблу користећи налог test
  2. Покрените ову команду у терминалу како бисте симулирали трансакцију из другог извора:
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
  1. Освежите страницу контролне табле у претраживачу
  2. Проверите да ли видите нову трансакцију

Шта овај тест показује:

  • Показује како localStorage може постати "застарео" (неажуран)
  • Симулација реалних сценарија где се подаци мењају ван ваше апликације
  • Открива тензију између перзистенције и свежине података

Изазов застарелости података:

Проблем Узрок Утицај на корисника
Застарели подаци localStorage се никада аутоматски не ажурира Корисници виде неажурне информације
Промене на серверу Друге апликације/корисници мењају исте податке Неконзистентни прикази на различитим платформама
Кеш vs. стварност Локални кеш не одговара стању сервера Лоше корисничко искуство и конфузија

Стратегија решења:

Имплементираћемо образац "освежавања при учитавању" који балансира предности перзистенције са потребом за свежим подацима. Овај приступ одржава глатко корисничко искуство уз осигурање тачности података.

Задатак: Имплементација система за освежавање података

Креираћемо систем који аутоматски преузима свежије податке са сервера, истовремено одржавајући предности нашег система за управљање перзистентним стањем.

Корак 1: Креирање ажурирача података о налогу

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);
}

Разумевање логике ове функције:

  • Проверава да ли је корисник тренутно пријављен (state.account постоји)
  • Преусмерава на одјаву ако не постоји валидна сесија
  • Преузима свежије податке о налогу са сервера користећи постојећу функцију getAccount()
  • Решава грешке сервера на одговарајући начин одјављивањем неважећих сесија
  • Ажурира стање са свежим подацима користећи наш контролисани систем ажурирања
  • Покреће аутоматску перзистенцију у localStorage кроз функцију updateState()

Корак 2: Креирање обрађивача за освежавање контролне табле

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

Шта ова функција за освежавање постиже:

  • Координира процес освежавања података и ажурирања корисничког интерфејса
  • Чека да се свежи подаци учитају пре ажурирања приказа
  • Осигурава да контролна табла приказује најновије информације
  • Одржава чисту поделу између управљања подацима и ажурирања корисничког интерфејса

Корак 3: Интеграција са системом рута

Ажурирајте конфигурацију рута како би се освежавање аутоматски покренуло:

const routes = {
  '/login': { templateId: 'login' },
  '/dashboard': { templateId: 'dashboard', init: refresh }
};

Како ова интеграција функционише:

  • Извршава функцију освежавања сваки пут када се учита рута контролне табле
  • Осигурава да се свежи подаци увек приказују када корисници навигирају на контролну таблу
  • Одржава постојећу структуру рута уз додавање свежине података
  • Пружа конзистентан образац за иницијализацију специфичну за руте

Тестирање вашег система за освежавање података:

  1. Пријавите се у вашу апликацију за банкарство
  2. Покрените curl команду из претходног примера да креирате нову трансакцију
  3. Освежите страницу контролне табле или навигирајте на другу руту па се вратите
  4. Проверите да ли се нова трансакција одмах приказује

🎉 Постигнут савршен баланс: Ваша апликација сада комбинује глатко искуство перзистентног стања са тачношћу свежих серверских података!

Изазов GitHub Copilot Agent 🚀

Користите Agent мод за решавање следећег изазова:

Опис: Имплементирајте свеобухватан систем за управљање стањем са функцијама за поништавање/поновно извршавање за апликацију за банкарство. Овај изазов ће вам помоћи да увежбате напредне концепте управљања стањем, укључујући праћење историје стања, непроменљива ажурирања и синхронизацију корисничког интерфејса.

Задатак: Креирајте побољшани систем за управљање стањем који укључује: 1) Низ историје стања који прати сва претходна стања, 2) Функције за поништавање и поновно извршавање које могу вратити претходна стања, 3) Дугмад у корисничком интерфејсу за операције поништавања/поновног извршавања на контролној табли, 4) Максимални лимит историје од 10 стања како би се спречили проблеми са меморијом, и 5) Правилно чишћење историје када се корисник одјави. Осигурајте да функције поништавања/поновног извршавања раде са променама стања рачуна и да се перзистирају током освежавања претраживача.

Сазнајте више о agent mode овде.

🚀 Изазов: Оптимизација складиштења

Ваша имплементација сада ефикасно управља корисничким сесијама, освежавањем података и стањем. Међутим, размислите да ли наш тренутни приступ оптимално балансира ефикасност складиштења са функционалношћу.

Као шаховски мајстори који разликују битне фигуре од оних које могу бити жртвоване, ефикасно управљање стањем захтева идентификацију података који морају бити перзистентни у односу на оне који увек треба да буду свежи са сервера.

Анализа оптимизације:

Оцените вашу тренутну имплементацију localStorage и размислите о овим стратешким питањима:

  • Које су минималне информације потребне за одржавање аутентификације корисника?
  • Који подаци се довољно често мењају да локално кеширање не пружа значајну корист?
  • Како оптимизација складиштења може побољшати перформансе без нарушавања корисничког искуства?

Стратегија имплементације:

  • Идентификујте битне податке који морају бити перзистентни (вероватно само идентификација корисника)
  • Модификујте вашу имплементацију localStorage да складишти само критичне податке о сесији
  • Осигурајте да се свежи подаци увек учитавају са сервера приликом посете контролној табли
  • Тестирајте да ваш оптимизовани приступ одржава исто корисничко искуство

Напредно разматрање:

  • Упоредите компромисе између складиштења комплетних података о налогу и само аутентификационих токена
  • Документујте ваше одлуке и разлоге за будуће чланове тима

Овај изазов ће вам помоћи да размишљате као професионални програмер који узима у обзир и корисничко искуство и ефикасност апликације. Узмите времена да експериментишете са различитим приступима!

Квиз након предавања

Квиз након предавања

Задатак

Имплементирајте дијалог "Додај трансакцију"

Ево примера резултата након завршетка задатка:

Снимак екрана који приказује пример дијалога "Додај трансакцију"


Одрицање од одговорности:
Овај документ је преведен помоћу услуге за превођење вештачке интелигенције Co-op Translator. Иако се трудимо да обезбедимо тачност, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на његовом изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални превод од стране људи. Не преузимамо одговорност за било каква погрешна тумачења или неспоразуме који могу произаћи из коришћења овог превода.