/blog/2022-07-10... > _
Image of Angular and NgRx logo

NgRx แƒแƒ“แƒแƒ›แƒ˜แƒแƒœแƒฃแƒ แƒแƒ“

แƒ•แƒ˜แƒ“แƒ”แƒแƒก แƒกแƒแƒœแƒแƒฎแƒแƒ•แƒแƒ“ แƒ’แƒแƒ“แƒแƒ“แƒ˜แƒ— แƒแƒ› แƒ‘แƒ›แƒฃแƒšแƒ–แƒ”

แƒจแƒ”แƒกแƒแƒ•แƒแƒšแƒ˜

แƒ—แƒฃ แƒแƒœแƒ’แƒฃแƒšแƒแƒ  แƒ“แƒ”แƒ•แƒ”แƒšแƒแƒžแƒ”แƒ แƒ˜แƒก แƒ•แƒแƒ™แƒแƒœแƒกแƒ˜แƒ”แƒ‘แƒ˜ แƒ“แƒแƒ’แƒ˜แƒ—แƒ•แƒแƒšแƒ˜แƒ”แƒ แƒ”แƒ‘แƒ˜แƒแƒ—, แƒแƒšแƒ‘แƒแƒ— แƒ’แƒ˜แƒœแƒแƒฎแƒแƒ•แƒ— แƒแƒฆแƒฌแƒ”แƒ แƒ, แƒกแƒแƒ“แƒแƒช NgRx-แƒ˜แƒก แƒชแƒแƒ“แƒœแƒ แƒ“แƒ˜แƒ“ แƒžแƒšแƒ˜แƒฃแƒกแƒแƒ“ แƒ˜แƒ—แƒ•แƒšแƒ”แƒ‘แƒ. แƒ›แƒ˜แƒฃแƒฎแƒ”แƒ“แƒแƒ•แƒแƒ“ แƒแƒ›แƒ˜แƒกแƒ, แƒ‘แƒ”แƒ•แƒ แƒ˜ แƒ“แƒแƒ›แƒฌแƒงแƒ”แƒ‘แƒ˜ แƒ“แƒ”แƒ•แƒ”แƒšแƒแƒžแƒ”แƒ แƒ˜ แƒแƒœ แƒ’แƒแƒฃแƒ แƒ‘แƒ˜แƒก NgRx-แƒก, แƒแƒœ แƒ›แƒ˜แƒกแƒ˜ แƒกแƒฌแƒแƒ•แƒšแƒ แƒฃแƒ‘แƒ แƒแƒšแƒแƒ“ แƒแƒ แƒแƒกแƒแƒญแƒ˜แƒ แƒแƒ“ แƒ›แƒ˜แƒแƒฉแƒœแƒ˜แƒ. แƒแƒ›แƒ˜แƒก แƒ‘แƒ แƒแƒšแƒ˜ แƒกแƒแƒ•แƒแƒ แƒแƒฃแƒ“แƒแƒ“ NgRx-แƒ˜แƒก แƒ”แƒ แƒ—แƒ˜ แƒจแƒ”แƒฎแƒ”แƒ“แƒ•แƒ˜แƒ— แƒ แƒ—แƒฃแƒšแƒ˜, แƒซแƒแƒšแƒ–แƒ”แƒ“ แƒฉแƒแƒฎแƒšแƒแƒ แƒ—แƒฃแƒšแƒ˜ แƒกแƒขแƒ แƒฃแƒฅแƒขแƒฃแƒ แƒแƒ. แƒกแƒ˜แƒœแƒแƒ›แƒ“แƒ•แƒ˜แƒšแƒ”แƒจแƒ˜ NgRx แƒแƒ แƒ˜แƒก แƒซแƒแƒšแƒ˜แƒแƒœ แƒ›แƒซแƒšแƒแƒ•แƒ แƒ˜ แƒฎแƒ”แƒšแƒกแƒแƒฌแƒงแƒ, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒแƒœแƒ’แƒฃแƒšแƒแƒ แƒ˜แƒ— แƒ“แƒ”แƒ•แƒ”แƒšแƒแƒžแƒ›แƒ”แƒœแƒขแƒก แƒซแƒแƒšแƒ–แƒ”แƒ“ แƒแƒ›แƒแƒ แƒขแƒ˜แƒ•แƒ”แƒ‘แƒก, แƒ’แƒแƒœแƒกแƒแƒ™แƒฃแƒ—แƒ แƒ”แƒ‘แƒ˜แƒ— แƒ“แƒ˜แƒ“ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ”แƒ‘แƒ–แƒ” แƒ’แƒฃแƒœแƒ“แƒฃแƒ แƒ˜ แƒ›แƒฃแƒจแƒแƒแƒ‘แƒ˜แƒก แƒ“แƒ แƒแƒก.

แƒ แƒ”แƒ™แƒแƒ›แƒ”แƒœแƒ“แƒ˜แƒ แƒ”แƒ‘แƒฃแƒšแƒ˜แƒ, แƒ แƒแƒ› แƒ˜แƒชแƒแƒ“แƒ”แƒ— Angular-แƒ˜แƒกแƒ แƒ“แƒ RxJs-แƒ˜แƒก แƒกแƒแƒคแƒฃแƒซแƒ•แƒšแƒ”แƒ‘แƒ˜, แƒกแƒแƒœแƒแƒ› NgRx-แƒก แƒ’แƒแƒ”แƒชแƒœแƒแƒ‘แƒ˜แƒ—.

แƒ แƒ แƒแƒ แƒ˜แƒก NgRx?

NgRx แƒแƒ แƒ˜แƒก แƒ‘แƒ˜แƒ‘แƒšแƒ˜แƒแƒ—แƒ”แƒ™แƒ, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒ’แƒ•แƒ”แƒฎแƒ›แƒแƒ แƒ”แƒ‘แƒ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ˜แƒก แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒก (State) แƒ›แƒ”แƒœแƒ”แƒฏแƒ›แƒ”แƒœแƒขแƒจแƒ˜. แƒ—แƒฃ แƒฌแƒแƒ แƒ›แƒแƒ•แƒ˜แƒ“แƒ’แƒ”แƒœแƒ—, แƒ แƒแƒ› แƒฉแƒ•แƒ”แƒœแƒ˜ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ แƒแƒ แƒ˜แƒก แƒ›แƒแƒœแƒฅแƒแƒœแƒ, แƒ›แƒแƒจแƒ˜แƒœ แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜ แƒแƒ แƒ˜แƒก แƒงแƒ•แƒ”แƒšแƒแƒคแƒ”แƒ แƒ˜, แƒ แƒ˜แƒกแƒ˜ แƒ›แƒ“แƒ’แƒแƒ›แƒแƒ แƒ”แƒแƒ‘แƒแƒช แƒจแƒ”แƒ˜แƒซแƒšแƒ”แƒ‘แƒ แƒ›แƒแƒœแƒฅแƒแƒœแƒแƒจแƒ˜ แƒจแƒ”แƒ˜แƒชแƒ•แƒแƒšแƒแƒก. แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒแƒ“, แƒกแƒแƒญแƒ˜แƒก, แƒžแƒแƒ–แƒ˜แƒชแƒ˜แƒ, แƒ›แƒ’แƒ–แƒแƒ•แƒ แƒ”แƒ‘แƒ˜แƒก แƒ แƒแƒแƒ“แƒ”แƒœแƒแƒ‘แƒ, แƒกแƒ˜แƒฉแƒฅแƒแƒ แƒ”, แƒžแƒ”แƒ“แƒšแƒ”แƒ‘แƒ˜, แƒกแƒแƒ แƒ™แƒ˜แƒก แƒžแƒแƒ–แƒ˜แƒชแƒ˜แƒ แƒ“แƒ แƒ.แƒจ. NgRx-แƒ˜แƒ— แƒกแƒ˜แƒกแƒขแƒ”แƒ›แƒฃแƒ แƒแƒ“ แƒ“แƒ แƒแƒ แƒ’แƒแƒœแƒ˜แƒ–แƒ”แƒ‘แƒฃแƒšแƒแƒ“ แƒจแƒ”แƒ’แƒ•แƒ˜แƒซแƒšแƒ˜แƒ แƒ’แƒแƒœแƒ•แƒกแƒแƒ–แƒฆแƒ•แƒ แƒแƒ—, แƒ แƒ แƒฃแƒœแƒ“แƒ แƒ’แƒแƒแƒ™แƒ”แƒ—แƒแƒก แƒ›แƒแƒœแƒฅแƒแƒœแƒแƒ›, แƒ แƒแƒชแƒ แƒ›แƒซแƒฆแƒแƒšแƒ˜ แƒ›แƒแƒœแƒฅแƒแƒœแƒแƒก แƒ“แƒแƒฅแƒแƒฅแƒแƒ•แƒก, แƒกแƒ˜แƒฉแƒฅแƒแƒ แƒ”แƒก แƒ’แƒแƒ“แƒแƒ แƒ—แƒแƒ•แƒก แƒแƒœ แƒกแƒแƒญแƒ”แƒก แƒ“แƒแƒแƒขแƒ แƒ˜แƒแƒšแƒ”แƒ‘แƒก.

แƒกแƒแƒ™แƒ•แƒแƒœแƒซแƒ แƒชแƒœแƒ”แƒ‘แƒ”แƒ‘แƒ˜

  • Action - แƒ”แƒฅแƒจแƒ”แƒœแƒ˜ แƒแƒ แƒ˜แƒก แƒฃแƒœแƒ˜แƒ™แƒแƒšแƒฃแƒ แƒ˜ แƒ›แƒแƒ•แƒšแƒ”แƒœแƒ แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒ’แƒแƒ˜แƒชแƒ”แƒ›แƒ แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ”แƒ‘แƒ˜แƒกแƒ แƒ“แƒ แƒกแƒ”แƒ แƒ•แƒ˜แƒกแƒ”แƒ‘แƒ˜แƒกแƒ’แƒแƒœ (แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒแƒ“ แƒกแƒ˜แƒแƒจแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ˜แƒก แƒ“แƒแƒ›แƒแƒขแƒ”แƒ‘แƒ, แƒฌแƒแƒจแƒšแƒ, แƒคแƒแƒ˜แƒšแƒ˜แƒก แƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒ แƒ“แƒ แƒกแƒฎแƒ•แƒ).
  • Reducer - แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒก แƒชแƒ•แƒšแƒ˜แƒšแƒ”แƒ‘แƒแƒก แƒฃแƒ–แƒ แƒฃแƒœแƒ•แƒ”แƒšแƒงแƒแƒคแƒก แƒฌแƒ›แƒ˜แƒœแƒ“แƒ แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ”แƒ‘แƒ˜แƒก แƒ”แƒ แƒ—แƒแƒ‘แƒšแƒ˜แƒแƒ‘แƒ, แƒ แƒแƒ›แƒ”แƒšแƒกแƒแƒช แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ˜ แƒ”แƒฌแƒแƒ“แƒ”แƒ‘แƒ. แƒ˜แƒกแƒ˜แƒœแƒ˜ แƒ˜แƒฆแƒ”แƒ‘แƒ”แƒœ แƒ›แƒ˜แƒ›แƒ“แƒ˜แƒœแƒแƒ แƒ” แƒกแƒ—แƒ”แƒ˜แƒ—แƒก แƒ“แƒ แƒฃแƒแƒฎแƒšแƒ”แƒก แƒ”แƒฅแƒจแƒ”แƒœแƒก, แƒ แƒแƒ—แƒ แƒ’แƒแƒ›แƒแƒ—แƒ•แƒแƒšแƒแƒœ แƒแƒฎแƒแƒšแƒ˜ แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜.
  • Selectors - แƒฌแƒ›แƒ˜แƒœแƒ“แƒ แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ”แƒ‘แƒ˜, แƒ แƒแƒ›แƒšแƒ”แƒ‘แƒ˜แƒช แƒ’แƒแƒ›แƒแƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒก แƒœแƒแƒฌแƒ˜แƒšแƒ”แƒ‘แƒ˜แƒก แƒแƒกแƒแƒฆแƒ”แƒ‘แƒแƒ“ แƒแƒœ แƒจแƒ”แƒกแƒแƒ“แƒ’แƒ”แƒœแƒแƒ“.
  • Store - แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜ แƒฎแƒ”แƒšแƒ›แƒ˜แƒกแƒแƒฌแƒ•แƒ“แƒแƒ›แƒ˜แƒ Store-แƒ˜แƒก แƒกแƒแƒจแƒฃแƒแƒšแƒ”แƒ‘แƒ˜แƒ—, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒก แƒ“แƒแƒ™แƒ•แƒ˜แƒ แƒ•แƒ”แƒ‘แƒแƒ“แƒ˜ แƒ˜แƒœแƒกแƒขแƒแƒœแƒชแƒ˜แƒแƒ แƒ“แƒ แƒแƒ›แƒแƒกแƒ—แƒแƒœแƒแƒ•แƒ” แƒ˜แƒก แƒ—แƒแƒ•แƒแƒ“ แƒแƒ™แƒ•แƒ˜แƒ แƒ“แƒ”แƒ‘แƒ แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒก.
  • Effects - แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜ แƒแƒ แƒ˜แƒก แƒ”แƒ แƒ—แƒ’แƒ•แƒแƒ แƒ˜ แƒ’แƒ•แƒ”แƒ แƒ“แƒ˜แƒ—แƒ˜ แƒ›แƒแƒ•แƒšแƒ”แƒœแƒ”แƒ‘แƒ˜, แƒ แƒแƒ›แƒšแƒ”แƒ‘แƒ˜แƒช แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒ˜แƒก แƒžแƒแƒ แƒแƒšแƒ”แƒšแƒฃแƒ แƒแƒ“ แƒฎแƒแƒ แƒชแƒ˜แƒ”แƒšแƒ“แƒ”แƒ‘แƒ. แƒ˜แƒกแƒ˜แƒœแƒ˜ แƒ”แƒ แƒ—แƒ˜ แƒ›แƒฎแƒ แƒ˜แƒ•, แƒฃแƒกแƒ›แƒ”แƒœแƒ”แƒœ แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒก, แƒ แƒแƒ—แƒ API-แƒก แƒ“แƒแƒฃแƒ™แƒแƒ•แƒจแƒ˜แƒ แƒ“แƒœแƒ”แƒœ แƒ“แƒ แƒกแƒแƒ—แƒแƒœแƒแƒ“แƒ แƒแƒžแƒ”แƒ แƒแƒชแƒ˜แƒ”แƒ‘แƒ˜ แƒฉแƒแƒแƒขแƒแƒ แƒแƒœ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ˜แƒก แƒ›แƒ˜แƒฆแƒ›แƒ, แƒฎแƒแƒšแƒ แƒ›แƒ”แƒแƒ แƒ” แƒ›แƒฎแƒ แƒ˜แƒ•, แƒ—แƒแƒ•แƒแƒ“ แƒ’แƒแƒกแƒชแƒ”แƒ›แƒ”แƒœ แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒก, แƒ แƒแƒชแƒ, แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒแƒ“ แƒฌแƒแƒ แƒ›แƒแƒขแƒ”แƒ‘แƒ˜แƒ— แƒ›แƒแƒ˜แƒžแƒแƒ•แƒ”แƒก แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ”แƒ‘แƒ˜, แƒ แƒแƒ›แƒšแƒ”แƒ‘แƒ˜แƒช แƒฃแƒœแƒ“แƒ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ˜แƒก แƒกแƒ—แƒ”แƒ˜แƒ—แƒจแƒ˜ แƒ’แƒแƒœแƒแƒ—แƒแƒ•แƒกแƒแƒœ.

แƒแƒ› แƒงแƒ•แƒ”แƒšแƒแƒคแƒ แƒ˜แƒก แƒกแƒแƒ˜แƒšแƒฃแƒกแƒขแƒ แƒแƒชแƒ˜แƒแƒ“ NgRx-แƒ˜แƒก แƒ“แƒแƒ™แƒฃแƒ›แƒ”แƒœแƒขแƒแƒชแƒ˜แƒ แƒ’แƒ•แƒ—แƒแƒ•แƒแƒ–แƒแƒ‘แƒก แƒจแƒ”แƒกแƒแƒœแƒ˜แƒจแƒœแƒแƒ• แƒกแƒฅแƒ”แƒ›แƒแƒก:

แƒแƒ›แƒแƒกแƒแƒ•แƒแƒš แƒฌแƒ”แƒ แƒขแƒ˜แƒšแƒแƒ“ แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜ แƒแƒ•แƒ˜แƒฆแƒแƒ— แƒ›แƒแƒ แƒชแƒฎแƒ”แƒœแƒ แƒฅแƒ•แƒ”แƒ“แƒ แƒ™แƒฃแƒ—แƒฎแƒ˜แƒ“แƒแƒœ. แƒ แƒแƒ’แƒแƒ แƒช แƒ•แƒฎแƒ”แƒ“แƒแƒ•แƒ—, แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜ แƒกแƒ”แƒšแƒ”แƒฅแƒขแƒแƒ แƒ˜แƒกแƒ’แƒแƒœ แƒ˜แƒฆแƒ”แƒ‘แƒก แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒก แƒจแƒ”แƒกแƒแƒฎแƒ”แƒ‘ แƒ˜แƒœแƒคแƒแƒ แƒ›แƒแƒชแƒ˜แƒแƒก, แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒแƒ“ แƒ’แƒแƒกแƒแƒ™แƒ”แƒ—แƒ”แƒ‘แƒ”แƒšแƒ˜ แƒกแƒแƒฅแƒ›แƒ”แƒ”แƒ‘แƒ˜แƒก แƒกแƒ˜แƒแƒก. แƒ—แƒแƒ•แƒ˜แƒก แƒ›แƒฎแƒ แƒ˜แƒ• แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜ แƒ’แƒแƒกแƒชแƒ”แƒ›แƒก แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒก, แƒกแƒแƒ“แƒแƒช แƒ˜แƒœแƒแƒฎแƒ”แƒ‘แƒ แƒ˜แƒœแƒคแƒแƒ แƒ›แƒแƒชแƒ˜แƒ, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒแƒฎแƒแƒš แƒกแƒ—แƒ”แƒ˜แƒ—แƒ–แƒ” แƒฃแƒœแƒ“แƒ แƒแƒ˜แƒกแƒแƒฎแƒแƒก, แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒแƒ“ แƒแƒฎแƒแƒšแƒ˜ แƒ’แƒแƒกแƒแƒ™แƒ”แƒ—แƒ”แƒ‘แƒ”แƒšแƒ˜แƒก แƒกแƒแƒฅแƒ›แƒ”. แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒ˜ แƒฃแƒ™แƒแƒ•แƒจแƒ˜แƒ แƒ“แƒ”แƒ‘แƒ แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ”แƒ‘แƒกแƒ แƒ“แƒ แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒก. แƒ—แƒฃ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ แƒ›แƒแƒชแƒ”แƒ›แƒฃแƒšแƒ˜ แƒ”แƒฅแƒจแƒ”แƒœแƒ˜แƒ— แƒแƒ  แƒฃแƒœแƒ“แƒ แƒ“แƒแƒฃแƒ™แƒแƒ•แƒจแƒ˜แƒ แƒ“แƒ”แƒก API-แƒก, แƒ›แƒแƒจแƒ˜แƒœ แƒ˜แƒก แƒžแƒ˜แƒ แƒ“แƒแƒžแƒ˜แƒ  แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒจแƒ˜ แƒ’แƒแƒ˜แƒ•แƒšแƒ˜แƒก, แƒ›แƒแƒ’แƒ แƒแƒ› แƒ—แƒฃ แƒกแƒ”แƒ แƒ•แƒ”แƒ แƒ—แƒแƒœ แƒ“แƒแƒ™แƒแƒ•แƒจแƒ˜แƒ แƒ”แƒ‘แƒ แƒ’แƒ•แƒญแƒ˜แƒ แƒ“แƒ”แƒ‘แƒ - แƒ•แƒ—แƒฅแƒ•แƒแƒ— แƒแƒฎแƒแƒšแƒ˜ แƒ’แƒแƒกแƒแƒ™แƒ”แƒ—แƒ”แƒ‘แƒ”แƒšแƒ˜ แƒกแƒแƒฅแƒ›แƒ” แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜ แƒฃแƒœแƒ“แƒ แƒแƒ•แƒกแƒแƒฎแƒแƒ— - แƒ›แƒแƒจแƒ˜แƒœ แƒ”แƒฅแƒจแƒ”แƒœแƒ˜ (แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ—แƒแƒœ แƒ”แƒ แƒ—แƒแƒ“) แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒกแƒแƒช แƒ’แƒแƒ˜แƒ•แƒšแƒ˜แƒก. แƒ—แƒฃแƒ›แƒชแƒ, แƒฃแƒคแƒ แƒ แƒกแƒฌแƒแƒ แƒ˜ แƒ˜แƒฅแƒœแƒ”แƒ‘แƒ แƒ˜แƒ›แƒ˜แƒก แƒ—แƒฅแƒ›แƒ, แƒ แƒแƒ› แƒแƒ› แƒ”แƒฅแƒจแƒ”แƒœแƒก แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜ แƒ“แƒแƒแƒคแƒ˜แƒฅแƒกแƒ˜แƒ แƒ”แƒ‘แƒก. แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒกแƒ—แƒแƒœ แƒ™แƒแƒ›แƒฃแƒœแƒ˜แƒ™แƒแƒชแƒ˜แƒ˜แƒก แƒžแƒแƒ แƒแƒšแƒ”แƒšแƒฃแƒ แƒแƒ“ แƒฉแƒ•แƒ”แƒœ แƒ’แƒ•แƒ˜แƒœแƒ“แƒ แƒ›แƒแƒ›แƒฎแƒ›แƒแƒ แƒ”แƒ‘แƒ”แƒšแƒก แƒ•แƒแƒฉแƒ•แƒ”แƒœแƒแƒ—, แƒ แƒแƒ› แƒแƒฎแƒแƒšแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ˜ แƒ›แƒแƒšแƒ” แƒฉแƒแƒ˜แƒขแƒ•แƒ˜แƒ แƒ—แƒ”แƒ‘แƒ, แƒแƒกแƒ”แƒ แƒแƒ› แƒ”แƒฅแƒจแƒ”แƒœแƒ›แƒ แƒ”แƒคแƒ”แƒฅแƒขแƒ—แƒแƒœ แƒ”แƒ แƒ—แƒแƒ“ แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ˜แƒช แƒฃแƒœแƒ“แƒ แƒ’แƒแƒ˜แƒแƒ แƒแƒก, แƒ แƒแƒ—แƒ แƒ›แƒแƒšแƒแƒ“แƒ˜แƒœแƒ˜แƒก แƒ›แƒ“แƒ’แƒแƒ›แƒแƒ แƒ”แƒแƒ‘แƒ แƒแƒกแƒแƒฎแƒแƒก แƒกแƒ—แƒ”แƒ˜แƒ—แƒจแƒ˜, แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒแƒ“ แƒฉแƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒ˜แƒก แƒกแƒžแƒ˜แƒœแƒ”แƒ แƒ˜. แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒœแƒ”แƒ‘แƒ˜ แƒ“แƒ แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜ แƒ”แƒ แƒ—แƒ›แƒแƒœแƒ”แƒ—แƒ—แƒแƒœ แƒแƒ แƒ›แƒฎแƒ แƒ˜แƒ•แƒแƒ“ แƒ“แƒแƒ™แƒแƒ•แƒจแƒ˜แƒ แƒ”แƒ‘แƒฃแƒšแƒ˜แƒ. แƒ”แƒก แƒ˜แƒ›แƒ˜แƒขแƒแƒ› แƒฎแƒ“แƒ”แƒ‘แƒ, แƒ แƒแƒ› แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜, แƒ แƒแƒชแƒ แƒ˜แƒกแƒ˜แƒœแƒ˜ แƒ”แƒฅแƒจแƒ”แƒœแƒก แƒ›แƒ˜แƒ˜แƒฆแƒ”แƒ‘แƒ”แƒœ, แƒกแƒ”แƒ แƒ•แƒ˜แƒกแƒก แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ”แƒœ, แƒ แƒแƒ—แƒ แƒ“แƒแƒฃแƒ™แƒแƒ•แƒจแƒ˜แƒ แƒ“แƒœแƒ”แƒœ API-แƒก แƒ“แƒ แƒ›แƒ˜แƒกแƒ’แƒแƒœ แƒ›แƒ˜แƒ˜แƒฆแƒแƒœ แƒžแƒแƒกแƒฃแƒฎแƒ˜, แƒฌแƒแƒ แƒ›แƒแƒขแƒ”แƒ‘แƒ˜แƒ— แƒ“แƒแƒ”แƒ›แƒแƒขแƒ แƒ—แƒฃ แƒแƒ แƒ แƒแƒฎแƒแƒšแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ˜. แƒ แƒแƒชแƒ แƒžแƒแƒกแƒฃแƒฎแƒก แƒ›แƒ˜แƒ˜แƒฆแƒ”แƒ‘แƒ”แƒœ, แƒ˜แƒกแƒ˜แƒœแƒ˜ แƒ—แƒแƒ•แƒแƒ“ แƒ’แƒแƒกแƒชแƒ”แƒ›แƒ”แƒœ แƒ”แƒฅแƒจแƒ”แƒœแƒก, แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒแƒ“ แƒ”แƒฅแƒจแƒ”แƒœแƒก, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒ’แƒ•แƒ”แƒฃแƒ‘แƒœแƒ”แƒ‘แƒ, แƒ แƒแƒ› แƒแƒฎแƒแƒšแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ˜ แƒฌแƒแƒ แƒ›แƒแƒขแƒ”แƒ‘แƒ˜แƒ— แƒ“แƒแƒ”แƒ›แƒแƒขแƒ แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒแƒจแƒ˜. แƒ”แƒก แƒ”แƒฅแƒจแƒ”แƒœแƒ˜แƒช แƒ’แƒแƒ˜แƒ•แƒšแƒ˜แƒก แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒก, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒแƒฎแƒแƒš แƒ“แƒแƒ›แƒแƒขแƒ”แƒ‘แƒฃแƒš แƒœแƒ˜แƒ•แƒ—แƒก แƒ›แƒแƒ›แƒฎแƒ›แƒแƒ แƒ”แƒ‘แƒšแƒ˜แƒก แƒกแƒ˜แƒแƒจแƒ˜ แƒแƒกแƒแƒฎแƒแƒ•แƒก, แƒฎแƒแƒšแƒ แƒฉแƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒ˜แƒก แƒกแƒžแƒ˜แƒœแƒ”แƒ แƒก - แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒžแƒ˜แƒ แƒ•แƒ”แƒšแƒ˜ แƒ”แƒฅแƒจแƒ”แƒœแƒ˜แƒ— แƒ’แƒแƒ•แƒแƒฉแƒ˜แƒœแƒ”แƒ— แƒกแƒ—แƒ”แƒ˜แƒ—แƒจแƒ˜ - แƒ’แƒแƒแƒฅแƒ แƒแƒ‘แƒก. แƒแƒ› แƒงแƒ•แƒ”แƒšแƒแƒคแƒ แƒ˜แƒก แƒ—แƒแƒ•แƒจแƒ˜ แƒแƒ แƒ˜แƒก แƒกแƒ—แƒแƒ แƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒฃแƒ™แƒแƒœแƒ แƒคแƒแƒœแƒ–แƒ” แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ”แƒ‘แƒ˜แƒก แƒ›แƒ˜แƒ”แƒ  แƒ’แƒแƒ“แƒแƒ›แƒฃแƒจแƒแƒ•แƒ”แƒ‘แƒฃแƒš แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ”แƒ‘แƒก แƒแƒกแƒแƒฎแƒแƒ•แƒก แƒกแƒ—แƒ”แƒ˜แƒ—แƒจแƒ˜ แƒ“แƒ แƒแƒ› แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒก แƒจแƒ”แƒกแƒแƒฎแƒ”แƒ‘ แƒ˜แƒœแƒคแƒแƒ แƒ›แƒแƒชแƒ˜แƒแƒก แƒ’แƒ•แƒแƒฌแƒ•แƒ“แƒ˜แƒก แƒกแƒ”แƒšแƒ”แƒฅแƒขแƒแƒ แƒ˜แƒก แƒกแƒแƒจแƒฃแƒแƒšแƒ”แƒ‘แƒ˜แƒ—. แƒแƒ› แƒฃแƒ™แƒแƒœแƒแƒกแƒ™แƒœแƒ”แƒšแƒก แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒก แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒกแƒ—แƒ”แƒ˜แƒ—แƒก แƒแƒกแƒแƒฎแƒแƒ•แƒก แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒแƒจแƒ˜. แƒแƒกแƒ” แƒจแƒ”แƒ˜แƒ™แƒ แƒ แƒฉแƒ•แƒ”แƒœแƒ˜ แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒก แƒ›แƒ”แƒœแƒ”แƒฏแƒ›แƒ”แƒœแƒขแƒ˜แƒก แƒชแƒ˜แƒ™แƒšแƒ˜. แƒžแƒ แƒแƒฅแƒขแƒ˜แƒ™แƒแƒจแƒ˜ แƒ”แƒก แƒงแƒ•แƒ”แƒšแƒแƒคแƒ”แƒ แƒ˜ แƒฃแƒคแƒ แƒ แƒœแƒแƒ—แƒ”แƒšแƒ˜ แƒ’แƒแƒฎแƒ“แƒ”แƒ‘แƒ.

แƒฉแƒ•แƒ”แƒœแƒ˜ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ

แƒ แƒแƒ—แƒ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ˜แƒก แƒแƒ’แƒ”แƒ‘แƒแƒ–แƒ” แƒ–แƒ”แƒ“แƒ›แƒ”แƒขแƒ˜ แƒ“แƒ แƒ แƒแƒ  แƒ“แƒแƒ•แƒฎแƒแƒ แƒฏแƒแƒ—, แƒ’แƒแƒ›แƒแƒ•แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ— แƒฌแƒ˜แƒœแƒแƒกแƒฌแƒแƒ  แƒแƒ’แƒ”แƒ‘แƒฃแƒš แƒžแƒ แƒแƒ”แƒฅแƒขแƒก, แƒ แƒแƒ›แƒšแƒ˜แƒก แƒ™แƒแƒ“แƒ˜แƒช แƒจแƒ”แƒ’แƒ˜แƒซแƒšแƒ˜แƒแƒ— แƒฉแƒแƒ›แƒแƒฌแƒ”แƒ แƒแƒ— แƒ’แƒ˜แƒ—แƒฐแƒแƒ‘แƒ˜แƒก แƒ แƒ”แƒžแƒแƒ–แƒ˜แƒขแƒแƒ แƒ˜แƒ˜แƒ“แƒแƒœ (ngrx-starter branch). แƒแƒ  แƒ“แƒแƒ’แƒแƒ•แƒ˜แƒฌแƒงแƒ“แƒ”แƒ— npm install แƒ‘แƒ แƒซแƒแƒœแƒ”แƒ‘แƒ˜แƒก แƒ’แƒแƒจแƒ•แƒ”แƒ‘แƒ. แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ แƒ‘แƒ”แƒฅแƒ”แƒœแƒ“แƒแƒ“ แƒšแƒแƒ™แƒแƒšแƒฃแƒ  แƒคแƒแƒ˜แƒšแƒก แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒก - database/db.json. แƒแƒ› แƒฃแƒ™แƒแƒœแƒแƒกแƒ™แƒœแƒ”แƒšแƒ˜แƒก แƒกแƒ”แƒ แƒ•แƒ”แƒ แƒ˜แƒ— แƒ’แƒแƒแƒฅแƒขแƒ˜แƒฃแƒ แƒ”แƒ‘แƒ แƒจแƒ”แƒ’แƒ˜แƒซแƒšแƒ˜แƒแƒ— แƒ‘แƒ แƒซแƒแƒœแƒ”แƒ‘แƒ˜แƒ— json-server --watch database/db.json. json-server แƒจแƒ”แƒ’แƒ•แƒ˜แƒฅแƒ›แƒœแƒ˜แƒก แƒšแƒแƒ™แƒแƒšแƒฃแƒ  แƒกแƒ”แƒ แƒ•แƒ”แƒ แƒก แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ—แƒ แƒ‘แƒแƒ–แƒ˜แƒ—, แƒ แƒแƒ›แƒ”แƒšแƒ—แƒแƒœแƒแƒช แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ HTTP แƒ›แƒแƒ—แƒฎแƒแƒ•แƒœแƒ”แƒ‘แƒก แƒ’แƒ–แƒแƒ•แƒœแƒ˜แƒก. แƒแƒ›แƒ˜แƒก แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒ›แƒ”แƒแƒ แƒ” แƒขแƒ”แƒ แƒ›แƒ˜แƒœแƒแƒšแƒ˜แƒก แƒ˜แƒœแƒกแƒขแƒแƒœแƒชแƒ˜แƒแƒจแƒ˜ แƒ’แƒแƒฃแƒจแƒ•แƒ˜แƒ— ng serve.

แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ˜แƒก แƒกแƒขแƒ แƒฃแƒฅแƒขแƒฃแƒ แƒ:

src/app
โ”œโ”€โ”€ app.component.css
โ”œโ”€โ”€ app.component.html
โ”œโ”€โ”€ app.component.ts          # แƒ›แƒ—แƒแƒ•แƒแƒ แƒ˜ แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜. แƒงแƒ•แƒ”แƒšแƒ แƒกแƒฎแƒ•แƒ แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜
โ”œโ”€โ”€ app.module.ts                 # แƒ›แƒแƒกแƒจแƒ˜แƒ แƒ’แƒแƒœแƒ—แƒแƒ•แƒกแƒ”แƒ‘แƒฃแƒšแƒ˜.
โ”œโ”€โ”€ input                     # แƒแƒฎแƒแƒšแƒ˜ แƒ’แƒแƒกแƒแƒ™แƒ”แƒ—แƒ”แƒ‘แƒšแƒ˜ แƒกแƒแƒฅแƒ›แƒ˜แƒก แƒ“แƒแƒกแƒแƒ›แƒแƒขแƒ”แƒ‘แƒ”แƒšแƒ˜ แƒ•แƒ”แƒšแƒ˜.
โ”‚   โ”œโ”€โ”€ input.component.css       # แƒฃแƒจแƒฃแƒแƒšแƒแƒ“ แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒก ItemsService-แƒก.
โ”‚   โ”œโ”€โ”€ input.component.html
โ”‚   โ””โ”€โ”€ input.component.ts
โ”œโ”€โ”€ item                      # แƒ’แƒแƒกแƒแƒ™แƒ”แƒ—แƒ”แƒ‘แƒ”แƒšแƒ˜ แƒกแƒแƒฅแƒ›แƒ˜แƒก แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜, แƒจแƒ”แƒ˜แƒชแƒแƒ•แƒก
โ”‚   โ”œโ”€โ”€ item.component.css        # แƒฌแƒแƒจแƒšแƒ˜แƒก แƒฆแƒ˜แƒšแƒแƒ™แƒก แƒ“แƒ แƒ’แƒแƒ“แƒแƒฎแƒแƒ–แƒ•แƒ˜แƒก แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒแƒก.
โ”‚   โ”œโ”€โ”€ item.component.html       # แƒฃแƒจแƒฃแƒแƒšแƒแƒ“ แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒก ItemsService-แƒก.
โ”‚   โ””โ”€โ”€ item.component.ts
โ”œโ”€โ”€ item.model.ts             # แƒ’แƒแƒกแƒแƒ™แƒ”แƒ—แƒ”แƒ‘แƒ”แƒšแƒ˜แƒก แƒกแƒแƒฅแƒ›แƒ˜แƒก แƒ›แƒแƒ“แƒ”แƒšแƒ˜
โ””โ”€โ”€ items.service.ts          # แƒกแƒ”แƒ แƒ•แƒ˜แƒกแƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒฃแƒ™แƒแƒ•แƒจแƒ˜แƒ“แƒ”แƒ‘แƒ API-แƒก

แƒแƒ  แƒ˜แƒฉแƒฅแƒแƒ แƒแƒ—, แƒ“แƒแƒแƒ—แƒ•แƒแƒšแƒ˜แƒ”แƒ แƒ”แƒ— แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ แƒ“แƒ แƒœแƒแƒฎแƒ”แƒ— แƒ แƒแƒ’แƒแƒ  แƒ›แƒฃแƒจแƒแƒแƒ‘แƒก แƒ›แƒ˜แƒกแƒ˜ แƒ—แƒ˜แƒ—แƒแƒ”แƒฃแƒšแƒ˜ แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜.

แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒแƒจแƒ˜ แƒ‘แƒ”แƒ•แƒ แƒ˜ แƒแƒ แƒแƒกแƒแƒกแƒฃแƒ แƒ•แƒ”แƒšแƒ˜ แƒžแƒแƒขแƒ”แƒ แƒœแƒ˜แƒ. แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒแƒ“, แƒกแƒ”แƒ แƒ•แƒ˜แƒกแƒ”แƒ‘แƒก แƒ—แƒ˜แƒ—แƒแƒ”แƒฃแƒšแƒ˜ แƒžแƒแƒขแƒแƒ แƒ แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜ แƒฃแƒจแƒฃแƒแƒšแƒแƒ“ แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒก. subscribe แƒ›แƒ”แƒ—แƒแƒ“แƒ˜ แƒ‘แƒ”แƒ•แƒ แƒฏแƒ”แƒ แƒแƒ แƒ’แƒแƒ›แƒแƒงแƒ”แƒœแƒ”แƒ‘แƒฃแƒšแƒ˜ ts แƒคแƒแƒ˜แƒšแƒ”แƒ‘แƒจแƒ˜. แƒแƒ›แƒแƒกแƒ—แƒแƒœแƒแƒ•แƒ”, แƒกแƒ”แƒ แƒ•แƒ˜แƒกแƒจแƒ˜ แƒ•แƒ”แƒงแƒ แƒ“แƒœแƒแƒ‘แƒ˜แƒ— แƒกแƒแƒ‘แƒฏแƒ”แƒฅแƒ—แƒ”แƒ‘แƒก, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒงแƒแƒ•แƒ”แƒš HTTP แƒ›แƒแƒ—แƒฎแƒแƒ•แƒœแƒแƒ–แƒ” แƒฃแƒœแƒ“แƒ แƒ“แƒแƒ•แƒแƒ”แƒ›แƒ˜แƒ—แƒแƒ— แƒ’แƒแƒœแƒแƒฎแƒšแƒ”แƒ‘แƒฃแƒšแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ”แƒ‘แƒ˜แƒก แƒกแƒ˜แƒ˜แƒ—, แƒ แƒแƒ›แƒ”แƒšแƒกแƒแƒช AppComponent แƒฃแƒกแƒ›แƒ”แƒœแƒก. NgRx แƒ“แƒแƒ’แƒ•แƒ”แƒฎแƒ›แƒแƒ แƒ”แƒ‘แƒ, แƒ แƒแƒ› แƒ“แƒ”แƒ•แƒ”แƒšแƒแƒžแƒ›แƒ”แƒœแƒขแƒ˜แƒก แƒกแƒแƒฃแƒ™แƒ”แƒ—แƒ”แƒกแƒ แƒžแƒแƒขแƒ”แƒ แƒœแƒ”แƒ‘แƒ˜ แƒ’แƒแƒ›แƒแƒ•แƒ˜แƒงแƒ”แƒœแƒแƒ—, แƒ แƒแƒ—แƒ แƒ›แƒแƒฅแƒกแƒ˜แƒ›แƒแƒšแƒฃแƒ แƒแƒ“ แƒแƒ•แƒแƒ แƒ˜แƒ“แƒแƒ— แƒ—แƒแƒ•แƒ˜ แƒ›แƒแƒฃแƒฌแƒ”แƒกแƒ แƒ˜แƒ’แƒ”แƒ‘แƒ”แƒš แƒ“แƒ แƒ’แƒแƒฃแƒ’แƒ”แƒ‘แƒแƒ  แƒ™แƒแƒ“แƒก.

แƒžแƒ˜แƒ แƒ•แƒ”แƒšแƒ˜ แƒœแƒแƒ‘แƒ˜แƒฏแƒ”แƒ‘แƒ˜

แƒ“แƒแƒ•แƒแƒ˜แƒœแƒกแƒขแƒแƒšแƒ˜แƒ แƒแƒ— NgRx. แƒฉแƒ•แƒ”แƒœ แƒ“แƒแƒ’แƒ•แƒญแƒ˜แƒ แƒ“แƒ”แƒ‘แƒ แƒ›แƒ—แƒแƒ•แƒแƒ แƒ˜ แƒ›แƒแƒ“แƒฃแƒšแƒ˜, ngrx/store แƒ“แƒ แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜แƒก แƒ›แƒแƒ“แƒฃแƒšแƒ˜ ngrx/effects. แƒแƒ›แƒแƒกแƒ—แƒแƒœแƒแƒ•แƒ” ngrx/store-devtools-แƒก แƒ’แƒแƒ›แƒแƒ•แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ— แƒ“แƒ”แƒ•แƒ”แƒšแƒแƒžแƒ›แƒ”แƒœแƒขแƒ˜แƒก แƒ“แƒ แƒแƒก, แƒ แƒแƒ—แƒ แƒ‘แƒ แƒแƒฃแƒ–แƒ”แƒ แƒ˜แƒ“แƒแƒœ แƒ“แƒแƒ•แƒแƒ™แƒ•แƒ˜แƒ แƒ“แƒ”แƒ— แƒกแƒ—แƒ”แƒ˜แƒ—แƒก. แƒแƒ›แƒ˜แƒกแƒแƒ—แƒ•แƒ˜แƒก แƒฅแƒ แƒแƒ›แƒ–แƒ” แƒ“แƒแƒ’แƒญแƒ˜แƒ แƒ“แƒ”แƒ‘แƒแƒ— Redux แƒ”แƒฅแƒกแƒ—แƒ”แƒœแƒจแƒ”แƒœแƒ˜แƒก แƒ“แƒแƒงแƒ”แƒœแƒ”แƒ‘แƒ.

npm install @ngrx/effects @ngrx/store @ngrx/store-devtools

แƒ“แƒแƒ•แƒแƒ แƒ”แƒ’แƒ˜แƒกแƒขแƒ แƒ˜แƒ แƒแƒ— แƒ˜แƒกแƒ˜แƒœแƒ˜ แƒ›แƒแƒ“แƒฃแƒšแƒจแƒ˜:

app.module.ts

// ... other imports
import { StoreModule } from "@ngrx/store";
import { StoreDevtoolsModule } from "@ngrx/store-devtools";

@NgModule({
  declarations: [AppComponent, ItemComponent, InputComponent],
  imports: [
    // ... other imports
    StoreModule.forRoot([]),
    StoreDevtoolsModule.instrument({
      maxAge: 25, // Retains last 25 states
      logOnly: environment.production,
      autoPause: true, // Pauses recording actions and state changes when the extension window is not open
    }),
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

แƒกแƒ—แƒแƒ แƒ˜แƒก แƒงแƒ•แƒ”แƒšแƒ แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜แƒกแƒ—แƒ•แƒ˜แƒก แƒฉแƒ•แƒ”แƒœ แƒชแƒแƒšแƒ™แƒ”แƒฃแƒšแƒ˜ แƒคแƒแƒšแƒ“แƒ”แƒ แƒ˜ แƒ’แƒ•แƒ”แƒฅแƒœแƒ”แƒ‘แƒ, แƒ แƒแƒ›แƒšแƒ”แƒ‘แƒ˜แƒช store-แƒ˜แƒก แƒคแƒแƒšแƒ“แƒ”แƒ แƒจแƒ˜ แƒ›แƒแƒ˜แƒงแƒ แƒ˜แƒแƒœ แƒ—แƒแƒ•แƒก.

src/app/store
โ”œโ”€โ”€ actions
โ”œโ”€โ”€ effects
โ”œโ”€โ”€ reducers
โ”œโ”€โ”€ selectors
โ”œโ”€โ”€ state
โ””โ”€โ”€ util

แƒแƒฎแƒšแƒ แƒ›แƒ—แƒแƒ•แƒแƒ แƒ˜ แƒ™แƒ˜แƒ—แƒฎแƒ•แƒแƒ แƒกแƒแƒ˜แƒ“แƒแƒœ แƒ“แƒแƒ•แƒ˜แƒฌแƒงแƒแƒ—. แƒ›แƒแƒฎแƒกแƒแƒ•แƒก แƒฉแƒ”แƒ›แƒ›แƒ แƒ›แƒ”แƒœแƒขแƒแƒ แƒ›แƒ แƒ”แƒ แƒ—แƒ˜ แƒจแƒ”แƒกแƒแƒœแƒ˜แƒจแƒœแƒแƒ•แƒ˜ แƒ แƒฉแƒ”แƒ•แƒ แƒ›แƒแƒ›แƒชแƒ NgRx-แƒก แƒ แƒแƒชแƒ แƒ•แƒ˜แƒ—แƒ•แƒ˜แƒกแƒ”แƒ‘แƒ“แƒ˜: โ€œแƒ—แƒฃ แƒแƒ  แƒ˜แƒชแƒ˜ แƒ แƒ˜แƒ—แƒ˜ แƒ“แƒแƒ˜แƒฌแƒงแƒ, แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒ˜แƒ— แƒ“แƒแƒ˜แƒฌแƒงแƒ”โ€.

แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒ˜แƒก แƒคแƒแƒšแƒ“แƒ”แƒ แƒจแƒ˜ แƒจแƒ”แƒ•แƒฅแƒ›แƒœแƒแƒ— todo.actions.ts. แƒแƒฎแƒšแƒ แƒ“แƒแƒ•แƒคแƒ˜แƒฅแƒ แƒ“แƒ”แƒ— แƒ˜แƒ›แƒแƒ–แƒ”, แƒ—แƒฃ แƒ แƒ แƒ›แƒแƒฅแƒ›แƒ”แƒ“แƒ”แƒ‘แƒ”แƒ‘แƒ˜ แƒจแƒ”แƒ˜แƒซแƒšแƒ”แƒ‘แƒ แƒ’แƒแƒœแƒแƒฎแƒแƒ แƒชแƒ˜แƒ”แƒšแƒแƒก แƒ›แƒแƒ›แƒฎแƒ›แƒแƒ แƒ”แƒ‘แƒ”แƒšแƒ›แƒ. แƒ›แƒแƒ›แƒฎแƒ›แƒแƒ แƒ”แƒ‘แƒ”แƒšแƒก แƒฃแƒœแƒ“แƒ แƒจแƒ”แƒ”แƒซแƒšแƒแƒก แƒœแƒ˜แƒ•แƒ—แƒ”แƒ‘แƒ˜แƒก แƒœแƒแƒฎแƒ•แƒ, แƒแƒฎแƒแƒšแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ˜แƒก แƒ“แƒแƒ›แƒแƒขแƒ”แƒ‘แƒ, แƒ›แƒ˜แƒกแƒ˜ แƒฌแƒแƒจแƒšแƒ แƒแƒœ แƒจแƒ”แƒชแƒ•แƒšแƒ.

store/actions/todo.actions.ts

import { createAction, props } from "@ngrx/store";
import { Item } from "src/app/item.model";

export const addItem = createAction(
  "[Todo Page] Add Item",
  props<{ description: string }>()
);

export const deleteItem = createAction(
  "[Todo Page] Delete Item",
  props<{ id: number }>()
);

export const updateItem = createAction(
  "[Todo Page] Update Item",
  props<{ item: Item }>()
);

export const getItems = createAction("[Todo Page] Get Items");

แƒฉแƒ•แƒ”แƒœ แƒ”แƒฅแƒจแƒ”แƒœแƒก แƒ•แƒแƒ”แƒฅแƒกแƒžแƒแƒ แƒขแƒ”แƒ‘แƒ— แƒ แƒแƒ’แƒแƒ แƒช แƒชแƒ•แƒšแƒแƒ“แƒก. แƒชแƒ•แƒšแƒแƒ“แƒ˜ แƒ—แƒแƒ•แƒ˜แƒก แƒ›แƒฎแƒ แƒ˜แƒ• แƒ˜แƒฅแƒ›แƒœแƒ”แƒ‘แƒ createAction แƒคแƒฃแƒฅแƒœแƒชแƒ˜แƒ˜แƒ—, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒžแƒแƒ แƒแƒ›แƒ”แƒขแƒ แƒแƒ“ แƒ˜แƒฆแƒ”แƒ‘แƒก แƒ”แƒฅแƒจแƒ”แƒœแƒ˜แƒก แƒขแƒ˜แƒžแƒก (แƒ›แƒ˜แƒก แƒ“แƒแƒฎแƒแƒกแƒ˜แƒแƒ—แƒ”แƒ‘แƒแƒก) แƒ“แƒ แƒžแƒ แƒแƒžแƒ”แƒ‘แƒก (แƒ˜แƒ› แƒ˜แƒœแƒคแƒแƒ แƒ›แƒแƒชแƒ˜แƒ˜แƒก แƒขแƒ˜แƒžแƒก, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒแƒ› แƒ”แƒฅแƒจแƒ”แƒœแƒก แƒฃแƒœแƒ“แƒ แƒ’แƒแƒ•แƒแƒขแƒแƒœแƒแƒ—). แƒ™แƒแƒœแƒ•แƒ”แƒœแƒชแƒ˜แƒฃแƒ แƒแƒ“ แƒ“แƒแƒกแƒแƒฌแƒงแƒ˜แƒกแƒจแƒ˜ แƒแƒ—แƒ™แƒฃแƒ—แƒฎแƒ”แƒ“ แƒคแƒ แƒฉแƒฎแƒ˜แƒšแƒ”แƒ‘แƒจแƒ˜ แƒ˜แƒฌแƒ”แƒ แƒ”แƒ‘แƒ แƒ”แƒฅแƒจแƒ”แƒœแƒ˜แƒก แƒแƒฆแƒ›แƒแƒชแƒ”แƒœแƒ”แƒ‘แƒ˜แƒก แƒฌแƒงแƒแƒ แƒ, แƒฉแƒ•แƒ”แƒœแƒ—แƒ•แƒ˜แƒก แƒ”แƒก แƒ˜แƒก แƒ’แƒ•แƒ”แƒ แƒ“แƒ˜แƒ, แƒกแƒแƒ“แƒแƒช แƒ’แƒแƒกแƒแƒ™แƒ”แƒ—แƒ”แƒ‘แƒ”แƒšแƒ˜ แƒกแƒแƒฅแƒ›แƒ”แƒ”แƒ‘แƒ˜แƒ แƒ’แƒแƒœแƒ—แƒแƒ•แƒกแƒ”แƒ‘แƒฃแƒšแƒ˜. แƒแƒ›แƒแƒก แƒ›แƒแƒฐแƒงแƒ•แƒ”แƒ‘แƒ แƒ”แƒฅแƒจแƒ”แƒœแƒ˜แƒก แƒ›แƒแƒ™แƒšแƒ” แƒ“แƒแƒฎแƒแƒกแƒ˜แƒแƒ—แƒ”แƒ‘แƒ. แƒฉแƒ•แƒ”แƒœ แƒ•แƒ˜แƒชแƒ˜แƒ—, แƒ แƒแƒ› แƒแƒฎแƒแƒšแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ˜แƒก แƒจแƒ”แƒฅแƒ›แƒœแƒ˜แƒกแƒแƒก แƒฃแƒœแƒ“แƒ แƒ›แƒ˜แƒ•แƒ˜แƒฆแƒแƒ— แƒœแƒ˜แƒ•แƒ—แƒ˜แƒก แƒแƒฆแƒฌแƒ”แƒ แƒ, แƒแƒ›แƒ˜แƒขแƒแƒ›แƒแƒช แƒ›แƒแƒก แƒžแƒ แƒแƒžแƒกแƒจแƒ˜ แƒ›แƒ˜แƒ•แƒฃแƒ—แƒ˜แƒ—แƒ”แƒ‘แƒ—, แƒ แƒแƒ’แƒแƒ แƒช แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ˜แƒก แƒขแƒ˜แƒžแƒก - แƒ›แƒแƒœ แƒฃแƒœแƒ“แƒ แƒ“แƒแƒแƒ‘แƒ แƒฃแƒœแƒแƒก แƒแƒ‘แƒ˜แƒ”แƒฅแƒขแƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒจแƒ˜แƒช แƒ˜แƒฅแƒœแƒ”แƒ‘แƒ แƒกแƒขแƒ แƒ˜แƒœแƒ’แƒ˜แƒก แƒขแƒ˜แƒžแƒ˜แƒก แƒคแƒ แƒแƒคแƒ”แƒ แƒ—แƒ˜ description. แƒ—แƒฃ แƒ”แƒฅแƒจแƒ”แƒœแƒ˜แƒก แƒžแƒ แƒแƒžแƒ”แƒ‘แƒ˜ แƒแƒ  แƒ’แƒ•แƒญแƒ˜แƒ แƒ“แƒ”แƒ‘แƒ, แƒ›แƒแƒก แƒฃแƒ‘แƒ แƒแƒšแƒแƒ“ แƒ’แƒแƒ›แƒแƒ•แƒขแƒแƒ•แƒ”แƒ‘แƒ—, แƒ แƒแƒ’แƒแƒ แƒช แƒ”แƒก getItems-แƒ˜แƒก แƒจแƒ”แƒ›แƒ—แƒฎแƒ•แƒ”แƒ•แƒแƒจแƒ˜แƒ.

แƒ”แƒฅแƒจแƒ”แƒœแƒ›แƒ แƒฃแƒœแƒ“แƒ แƒ’แƒแƒ˜แƒแƒ แƒแƒก แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ˜ แƒ“แƒ แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜. แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ˜ แƒ’แƒ•แƒ˜แƒœแƒ“แƒ แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒก แƒฃแƒจแƒฃแƒแƒšแƒแƒ“ แƒจแƒ”แƒกแƒแƒชแƒ•แƒšแƒ”แƒšแƒแƒ“, แƒฎแƒแƒšแƒ แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜ API-แƒกแƒ—แƒแƒœ แƒ“แƒแƒกแƒแƒ™แƒแƒ•แƒจแƒ˜แƒ แƒ”แƒ‘แƒšแƒแƒ“. API-แƒกแƒ—แƒแƒœ แƒฃแƒ แƒ—แƒ˜แƒ”แƒ แƒ—แƒแƒ‘แƒแƒจแƒ˜ แƒฉแƒ•แƒ”แƒœ แƒฎแƒจแƒ˜แƒ แƒแƒ“ แƒแƒ แƒ˜ แƒขแƒ˜แƒžแƒ˜แƒก แƒ”แƒฅแƒจแƒ”แƒœแƒ˜ แƒ’แƒ•แƒแƒฅแƒ•แƒก: แƒฌแƒแƒ แƒ›แƒแƒขแƒ”แƒ‘แƒ˜แƒก แƒ“แƒ แƒ”แƒ แƒแƒ แƒ˜แƒก แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒ˜. แƒ—แƒ˜แƒ—แƒแƒ”แƒฃแƒšแƒ˜ แƒ›แƒแƒ›แƒฎแƒแƒ แƒ”แƒ‘แƒšแƒ˜แƒก แƒ”แƒฅแƒจแƒ”แƒœแƒ˜แƒก แƒกแƒแƒคแƒฃแƒซแƒ•แƒ”แƒšแƒ–แƒ”, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช API-แƒกแƒ—แƒแƒœ แƒ™แƒแƒ•แƒจแƒ˜แƒ แƒก แƒกแƒแƒญแƒ˜แƒ แƒแƒ”แƒ‘แƒก, แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜ แƒกแƒแƒžแƒแƒกแƒฃแƒฎแƒแƒ“ แƒ’แƒแƒกแƒชแƒ”แƒ›แƒ”แƒœ แƒแƒ› แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒก. แƒ›แƒแƒ—แƒ—แƒ•แƒ˜แƒก แƒชแƒแƒšแƒ™แƒ” แƒคแƒแƒ˜แƒšแƒจแƒ˜ แƒ’แƒแƒ•แƒฌแƒ”แƒ แƒแƒ— แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒ˜:

store/actions/todo-api.actions.ts

import { createAction, props } from "@ngrx/store";
import { Item } from "src/app/item.model";

export const getItemsSuccessful = createAction(
  "[Todo Api] Get Items Successful",
  props<{ items: Item[] }>()
);

export const getItemsFailed = createAction(
  "[Todo Api] Get Items Failed",
  props<{ error: string }>()
);

export const addItemSuccessful = createAction(
  "[Todo Api] Add Item Successful",
  props<{ item: Item }>()
);

export const addItemFailed = createAction(
  "[Todo Api] Add Item Failed",
  props<{ error: string }>()
);

export const updateItemSuccessful = createAction(
  "[Todo Api] Update Item Successful",
  props<{ item: Item }>()
);

export const updateItemFailed = createAction(
  "[Todo Api] Update Item Failed",
  props<{ error: string }>()
);

export const deleteItemSuccessful = createAction(
  "[Todo Api] Delete Item Successful",
  props<{ id: number }>()
);

export const deleteItemFailed = createAction(
  "[Todo Api] Delete Item Failed",
  props<{ error: string }>()
);

แƒกแƒ˜แƒšแƒแƒ›แƒแƒ–แƒ˜แƒกแƒ—แƒ•แƒ˜แƒก แƒ˜แƒ›แƒแƒ•แƒ” แƒคแƒแƒšแƒ“แƒ”แƒ แƒจแƒ˜ index.ts แƒจแƒ”แƒ•แƒฅแƒ›แƒœแƒแƒ—, แƒกแƒแƒ˜แƒ“แƒแƒœแƒแƒช แƒ“แƒแƒ•แƒแƒ”แƒฅแƒกแƒžแƒแƒ แƒขแƒ”แƒ‘แƒ— แƒงแƒ•แƒ”แƒšแƒ แƒ”แƒฅแƒจแƒ”แƒœแƒก, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒ˜แƒก แƒ”แƒ แƒ—แƒ˜ แƒคแƒแƒšแƒ“แƒ”แƒ แƒจแƒ˜ แƒ˜แƒฅแƒœแƒ”แƒ‘แƒ แƒœแƒ”แƒ˜แƒ›แƒกแƒคแƒ”แƒ˜แƒกแƒ˜แƒ— (Namespace), TodoActions แƒฎแƒแƒšแƒ แƒ›แƒ”แƒแƒ แƒ”แƒจแƒ˜ TodoApiActions. แƒแƒกแƒ” แƒ›แƒแƒ•แƒ˜แƒฅแƒชแƒ”แƒ•แƒ˜แƒ— แƒกแƒ—แƒแƒ แƒ˜แƒก แƒงแƒ•แƒ”แƒšแƒ แƒ”แƒšแƒ”แƒ›แƒ”แƒœแƒขแƒ˜แƒกแƒ—แƒ•แƒ˜แƒก.

store/actions/index.ts

export * as TodoActions from "./todo.actions";
export * as TodoApiActions from "./todo-api.actions";

แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒแƒ“, แƒแƒฎแƒแƒšแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ˜แƒก แƒจแƒ”แƒฅแƒ›แƒœแƒ˜แƒก แƒ”แƒฅแƒจแƒ”แƒœแƒ›แƒ (addItem) แƒฃแƒจแƒฃแƒแƒšแƒแƒ“ แƒกแƒ—แƒ”แƒ˜แƒ—แƒจแƒ˜ แƒ›แƒฎแƒแƒšแƒแƒ“ แƒ˜แƒก แƒฃแƒœแƒ“แƒ แƒแƒกแƒแƒฎแƒแƒก, แƒ แƒแƒ› แƒ›แƒ˜แƒ›แƒ“แƒ˜แƒœแƒแƒ แƒ”แƒแƒ‘แƒก API-แƒกแƒ’แƒแƒœ แƒžแƒแƒกแƒฃแƒฎแƒ˜แƒก แƒ›แƒแƒšแƒแƒ“แƒ˜แƒœแƒ˜. แƒแƒ›แƒ˜แƒก แƒจแƒ”แƒ›แƒ“แƒ”แƒ’, แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ›แƒ แƒฃแƒœแƒ“แƒ แƒ“แƒแƒแƒคแƒ˜แƒฅแƒกแƒ˜แƒ แƒแƒœ แƒ”แƒก แƒ”แƒฅแƒจแƒ”แƒœแƒ˜, แƒ›แƒแƒ—แƒฎแƒแƒ•แƒœแƒ แƒ’แƒแƒ’แƒ–แƒแƒ•แƒœแƒแƒœ แƒกแƒ”แƒ แƒ•แƒ”แƒ แƒ–แƒ” แƒ“แƒ แƒ’แƒแƒกแƒชแƒ”แƒœ แƒแƒฎแƒแƒšแƒ˜ แƒ”แƒฅแƒจแƒ”แƒœแƒ˜ addItemSuccessful, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒก prop-แƒกแƒแƒช แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ˜ แƒกแƒ—แƒ”แƒ˜แƒ—แƒจแƒ˜ แƒ’แƒแƒœแƒแƒ—แƒแƒ•แƒกแƒ”แƒ‘แƒก. แƒฏแƒ”แƒ  แƒœแƒ˜แƒ•แƒ—แƒ”แƒ‘แƒ˜แƒก แƒแƒฆแƒ”แƒ‘แƒ˜แƒก แƒ”แƒฅแƒจแƒ”แƒœแƒกแƒ แƒ“แƒ แƒ›แƒแƒšแƒแƒ“แƒ˜แƒœแƒ˜แƒก แƒกแƒ—แƒ”แƒ˜แƒ—แƒก แƒ›แƒ˜แƒ•แƒฎแƒ”แƒ“แƒแƒ—. แƒจแƒ”แƒ•แƒฅแƒ›แƒœแƒแƒ— แƒฉแƒ•แƒ”แƒœแƒ˜ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ˜แƒก แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒก แƒขแƒ˜แƒžแƒ˜, แƒ แƒแƒ›แƒšแƒ˜แƒ—แƒแƒช แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ˜ แƒ˜แƒฎแƒ”แƒšแƒ›แƒซแƒฆแƒ•แƒแƒœแƒ”แƒšแƒ”แƒ‘แƒก:

store/state/todo.state.ts

import { Item } from "src/app/item.model";

export interface TodoState {
  items: Item[];
  loading: boolean;
  error: string;
}

แƒกแƒ—แƒ”แƒ˜แƒ—แƒจแƒ˜ แƒ’แƒ•แƒ˜แƒœแƒ“แƒ แƒœแƒ˜แƒ•แƒ—แƒ”แƒ‘แƒ˜แƒก แƒกแƒ˜แƒ, แƒฉแƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒ แƒ›แƒ˜แƒ›แƒ“แƒ˜แƒœแƒแƒ แƒ”แƒแƒ‘แƒก แƒ—แƒฃ แƒแƒ แƒ แƒ“แƒ แƒแƒ แƒกแƒ”แƒ‘แƒแƒ‘แƒก แƒ—แƒฃ แƒแƒ แƒ แƒ”แƒ แƒแƒ แƒ˜. แƒ”แƒกแƒ”แƒช แƒ“แƒแƒ•แƒแƒ”แƒฅแƒกแƒžแƒแƒ แƒขแƒแƒ— index.ts-แƒ“แƒแƒœ.

store/state/index.ts

export * from "./todo.state";

แƒแƒฎแƒšแƒ แƒจแƒ”แƒ•แƒฅแƒ›แƒœแƒแƒ— แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ˜:

store/state/reducers/todo.reducer.ts

import { createReducer, on } from "@ngrx/store";
import { TodoActions } from "../actions";
import { TodoState } from "../state";

const initialState: TodoState = {
  items: [],
  loading: false,
  error: "",
};

export const todoReducer = createReducer(
  initialState,
  // Get Items
  on(TodoActions.getItems, (state) => ({ ...state, loading: true }))
  on(TodoApiActions.getItemsSuccessful, (state, { items }) => ({
    ...state,
    items: items,
    loading: false,
  })),
  on(TodoApiActions.getItemsFailed, (state, { error }) => ({
    ...state,
    error: error,
    loading: false,
  })),
);

แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ˜ แƒ˜แƒฅแƒ›แƒœแƒ”แƒ‘แƒ createReducer แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ˜แƒ—, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒžแƒ˜แƒ แƒ•แƒ”แƒš แƒแƒ แƒ’แƒฃแƒ›แƒ”แƒœแƒขแƒแƒ“ แƒžแƒ˜แƒ แƒ•แƒแƒœแƒ“แƒ”แƒš แƒกแƒ—แƒ”แƒ˜แƒ—แƒก แƒ˜แƒฆแƒ”แƒ‘แƒก. แƒžแƒ˜แƒ แƒ•แƒแƒœแƒ“แƒ”แƒš แƒกแƒ—แƒ”แƒ˜แƒ—แƒก แƒฉแƒ•แƒ”แƒœ แƒ˜แƒœแƒ˜แƒชแƒ˜แƒแƒšแƒ˜แƒ–แƒแƒชแƒ˜แƒแƒก แƒ•แƒฃแƒ™แƒ”แƒ—แƒ”แƒ‘แƒ— แƒแƒ›แƒแƒ•แƒ” แƒคแƒแƒ˜แƒšแƒจแƒ˜. แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ แƒžแƒ˜แƒ แƒ•แƒแƒœแƒ“แƒ”แƒš แƒ›แƒ“แƒ’แƒแƒ›แƒแƒ แƒ”แƒแƒ‘แƒแƒจแƒ˜ แƒจแƒ”แƒ˜แƒชแƒแƒ•แƒก แƒœแƒ˜แƒ•แƒ—แƒ”แƒ‘แƒ˜แƒก แƒชแƒแƒ แƒ˜แƒ”แƒš แƒกแƒ˜แƒแƒก, แƒฉแƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒแƒก แƒฃแƒแƒ แƒงแƒแƒคแƒ˜แƒ—แƒ˜ แƒ›แƒœแƒ˜แƒจแƒ•แƒœแƒ”แƒšแƒแƒ‘แƒ˜แƒ— แƒ“แƒ แƒ”แƒ แƒแƒ แƒก, แƒ แƒแƒ’แƒแƒ แƒช แƒชแƒแƒ แƒ˜แƒ”แƒš แƒกแƒขแƒ แƒ˜แƒœแƒ’แƒก. แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒแƒ แƒ’แƒฃแƒ›แƒ”แƒœแƒขแƒ”แƒ‘แƒแƒ“ แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ˜ แƒ˜แƒฆแƒ”แƒ‘แƒก on แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ”แƒ‘แƒก. on แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ”แƒ‘แƒ˜ แƒ’แƒแƒœแƒกแƒแƒ–แƒฆแƒ•แƒ แƒแƒ•แƒก แƒ—แƒ˜แƒ—แƒแƒ”แƒฃแƒšแƒ˜ แƒ”แƒฅแƒจแƒ”แƒœแƒ˜แƒก แƒกแƒแƒคแƒฃแƒซแƒ•แƒ”แƒšแƒ–แƒ” (แƒžแƒ˜แƒ แƒ•แƒ”แƒšแƒ˜ แƒแƒ แƒ’แƒฃแƒ›แƒ”แƒœแƒขแƒ˜) แƒ แƒแƒ’แƒแƒ  แƒฃแƒœแƒ“แƒ แƒจแƒ”แƒ˜แƒชแƒ•แƒแƒšแƒแƒก แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜ (แƒ›แƒ”แƒแƒ แƒ” แƒแƒ แƒ’แƒฃแƒ›แƒ”แƒœแƒขแƒ˜ แƒฅแƒแƒšแƒ‘แƒ”แƒฅแƒ˜แƒก แƒคแƒแƒ แƒ›แƒ˜แƒ—). แƒฅแƒแƒšแƒ‘แƒ”แƒฅ แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒแƒจแƒ˜ แƒ•แƒแƒ‘แƒ แƒฃแƒœแƒ”แƒ‘แƒ— แƒกแƒ—แƒ”แƒ˜แƒ—แƒก แƒ“แƒแƒกแƒžแƒ แƒ”แƒ“แƒ˜แƒšแƒ˜ แƒคแƒแƒ แƒ›แƒ˜แƒ—, แƒ แƒแƒ—แƒ แƒงแƒแƒ•แƒ”แƒšแƒ›แƒ แƒแƒฎแƒแƒšแƒ›แƒ แƒ”แƒฅแƒจแƒ”แƒœแƒ›แƒ แƒจแƒ”แƒ˜แƒœแƒแƒ แƒฉแƒฃแƒœแƒแƒก แƒ“แƒ แƒแƒ  แƒฌแƒแƒจแƒแƒšแƒแƒก แƒฌแƒ˜แƒœแƒ แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜. แƒ›แƒแƒก แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒแƒ‘แƒ˜แƒ”แƒฅแƒขแƒจแƒ˜ แƒฉแƒ•แƒ”แƒœแƒ—แƒ•แƒ˜แƒก แƒกแƒแƒกแƒฃแƒ แƒ•แƒ”แƒš แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒก แƒœแƒแƒฌแƒ˜แƒšแƒ”แƒ‘แƒก แƒ›แƒœแƒ˜แƒจแƒ•แƒœแƒ”แƒšแƒแƒ‘แƒแƒก แƒจแƒ”แƒ•แƒฃแƒชแƒ•แƒšแƒ˜แƒ—. แƒ แƒแƒชแƒ แƒ›แƒแƒ›แƒฎแƒ›แƒแƒ แƒ”แƒ‘แƒ”แƒšแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ”แƒ‘แƒ˜แƒก แƒ›แƒ˜แƒฆแƒ”แƒ‘แƒ˜แƒก แƒ”แƒฅแƒจแƒ”แƒœแƒก แƒ’แƒแƒœแƒแƒฎแƒแƒ แƒชแƒ˜แƒ”แƒšแƒ”แƒ‘แƒก, แƒฉแƒ•แƒ”แƒœ แƒฃแƒœแƒ“แƒ แƒ’แƒแƒ›แƒแƒ•แƒแƒฉแƒ˜แƒœแƒแƒ— แƒ›แƒแƒšแƒแƒ“แƒ˜แƒœแƒ˜แƒก แƒ›แƒ“แƒ’แƒแƒ›แƒแƒ แƒ”แƒแƒ‘แƒ, แƒ›แƒแƒจแƒแƒกแƒแƒ“แƒแƒ›แƒ” loading-แƒก แƒ’แƒแƒ•แƒฎแƒ“แƒ˜แƒ— แƒญแƒ”แƒจแƒ›แƒแƒ แƒ˜แƒขแƒก. แƒแƒ›แƒ˜แƒก แƒกแƒแƒคแƒฃแƒซแƒ•แƒ”แƒšแƒ–แƒ” แƒฉแƒ•แƒ”แƒœ แƒฃแƒœแƒ“แƒ แƒ’แƒแƒ›แƒแƒ•แƒแƒฉแƒ˜แƒœแƒแƒ— แƒ•แƒ”แƒ‘-แƒ’แƒ•แƒ”แƒ แƒ“แƒ–แƒ” แƒฉแƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒ˜แƒก แƒกแƒžแƒ˜แƒœแƒ”แƒ แƒ˜. แƒœแƒ˜แƒ•แƒ—แƒ”แƒ‘แƒ˜แƒก แƒฌแƒแƒ แƒ›แƒแƒขแƒ”แƒ‘แƒ˜แƒ— แƒ›แƒ˜แƒฆแƒ”แƒ‘แƒ˜แƒก แƒจแƒ”แƒ›แƒ—แƒฎแƒ•แƒ”แƒ•แƒแƒจแƒ˜, แƒฉแƒ•แƒ”แƒœ แƒฃแƒœแƒ“แƒ แƒแƒ› แƒ”แƒฅแƒจแƒ”แƒœแƒ˜แƒก props-แƒ˜แƒ“แƒแƒœ แƒ›แƒ˜แƒฆแƒ”แƒ‘แƒฃแƒšแƒ˜ แƒแƒฎแƒแƒšแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ˜ แƒกแƒ—แƒ”แƒ˜แƒ—แƒจแƒ˜ แƒ’แƒแƒœแƒ•แƒแƒ—แƒแƒ•แƒกแƒแƒ—, แƒฎแƒแƒšแƒ loading แƒ’แƒแƒ•แƒฎแƒแƒ“แƒแƒ— แƒ›แƒชแƒ“แƒแƒ แƒ˜. แƒ›แƒแƒ’แƒ แƒแƒ› แƒ แƒแƒ’แƒแƒ  แƒแƒ•แƒ˜แƒฆแƒแƒ— loading แƒคแƒ แƒแƒคแƒ”แƒ แƒ—แƒ˜ แƒแƒœ items แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒ“แƒแƒœ? แƒกแƒ”แƒšแƒ”แƒฅแƒขแƒแƒ แƒ”แƒ‘แƒ˜แƒก แƒกแƒแƒจแƒฃแƒแƒšแƒ”แƒ‘แƒ˜แƒ—! แƒ›แƒแƒ’แƒ แƒแƒ› แƒฏแƒ”แƒ  แƒฉแƒ•แƒ”แƒœแƒ˜ แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ˜ แƒ“แƒแƒ•แƒแƒ แƒ”แƒ’แƒ˜แƒกแƒขแƒ แƒ˜แƒ แƒแƒ— แƒ›แƒแƒ“แƒฃแƒšแƒจแƒ˜, แƒ แƒแƒ—แƒ แƒแƒœแƒ’แƒฃแƒšแƒแƒ แƒ›แƒ แƒ˜แƒก แƒ“แƒแƒแƒคแƒ˜แƒฅแƒกแƒ˜แƒ แƒแƒก.

store/state/reducers/index.ts

export * from "./todo.reducer";

app.module.ts

// ... other imports
import { StoreModule } from "@ngrx/store";
import { todoReducer } from "./store/reducers";
import { StoreDevtoolsModule } from "@ngrx/store-devtools";

@NgModule({
  declarations: [AppComponent, ItemComponent, InputComponent],
  imports: [
    // ... other imports
    StoreModule.forRoot({ todo: todoReducer }),
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

แƒจแƒ”แƒœแƒ˜แƒจแƒ•แƒœแƒ: แƒ—แƒฃ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒแƒจแƒ˜ แƒกแƒฎแƒ•แƒ แƒ™แƒแƒœแƒ™แƒ แƒ”แƒขแƒฃแƒšแƒ˜ แƒ›แƒแƒ“แƒฃแƒšแƒ”แƒ‘แƒ˜แƒช แƒ’แƒ•แƒแƒฅแƒ•แƒก, app.module.ts-แƒจแƒ˜ forRoot แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ แƒ“แƒแƒ แƒฉแƒ”แƒ‘แƒ แƒชแƒแƒ แƒ˜แƒ”แƒšแƒ˜, แƒฎแƒแƒšแƒ แƒกแƒฎแƒ•แƒ feature แƒ›แƒแƒ“แƒฃแƒšแƒ”แƒ‘แƒจแƒ˜, แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒแƒ“ แƒ—แƒฃ แƒ’แƒ•แƒแƒฅแƒ•แƒก แƒชแƒแƒšแƒ™แƒ” notes แƒ“แƒ todo feature-แƒ”แƒ‘แƒ˜, แƒ’แƒ•แƒ”แƒฅแƒœแƒ”แƒ‘แƒ StoreModule.forFeature({ notes: notesreducer }) แƒ“แƒ StoreModule.forFeature({ todo: todoreducer }). แƒฃแƒ›แƒฏแƒแƒ‘แƒ”แƒกแƒ˜แƒ, แƒ แƒแƒ› แƒงแƒ•แƒ”แƒšแƒ feature module-แƒก แƒ—แƒแƒ•แƒ˜แƒกแƒ˜ แƒกแƒ—แƒแƒ แƒ˜ แƒฐแƒฅแƒแƒœแƒ“แƒ”แƒก.

แƒฉแƒ•แƒ”แƒœ แƒแƒœแƒ’แƒฃแƒšแƒแƒ แƒก แƒ•แƒ”แƒฃแƒ‘แƒœแƒ”แƒ‘แƒ˜แƒ—, แƒ แƒแƒ› แƒ•แƒแƒ แƒ”แƒ’แƒ˜แƒกแƒขแƒ แƒ˜แƒ แƒ”แƒ‘แƒ— แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒก, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒแƒกแƒแƒชแƒ˜แƒ แƒ”แƒ‘แƒฃแƒšแƒ˜ แƒ˜แƒฅแƒœแƒ”แƒ‘แƒ แƒกแƒแƒฎแƒ”แƒšแƒ—แƒแƒœ โ€œtodoโ€. แƒ”แƒก แƒฃแƒ™แƒแƒœแƒแƒกแƒ™แƒœแƒ”แƒšแƒ˜ แƒ“แƒแƒ’แƒ•แƒญแƒ˜แƒ แƒ“แƒ”แƒ‘แƒ แƒกแƒ”แƒšแƒ”แƒฅแƒขแƒแƒ แƒ”แƒ‘แƒ˜แƒก แƒจแƒ”แƒกแƒแƒฅแƒ›แƒœแƒ”แƒšแƒแƒ“.

store/state/selectors/todo.selectors.ts

import { createFeatureSelector, createSelector } from "@ngrx/store";
import { TodoState } from "../state";

export const selectTodo = createFeatureSelector<TodoState>("todo");

export const selectLoading = createSelector(
  selectTodo,
  (state: TodoState) => state.loading
);

export const selectItems = createSelector(
  selectTodo,
  (state: TodoState) => state.items
);

export const selectError = createSelector(
  selectTodo,
  (state: TodoState) => state.error
);

createFeatureSelector-แƒ˜แƒก แƒกแƒแƒจแƒฃแƒแƒšแƒ”แƒ‘แƒ˜แƒ— แƒฉแƒ•แƒ”แƒœ แƒกแƒ”แƒšแƒ”แƒฅแƒขแƒแƒ แƒก แƒ•แƒฅแƒ›แƒœแƒ˜แƒ— แƒ™แƒแƒœแƒ™แƒ แƒ”แƒขแƒฃแƒšแƒ˜ feature-แƒ˜แƒกแƒ—แƒ•แƒ˜แƒก. แƒฉแƒ•แƒ”แƒœ แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒก แƒ›แƒแƒ“แƒฃแƒšแƒจแƒ˜ แƒแƒกแƒแƒชแƒ˜แƒแƒชแƒ˜แƒ แƒ’แƒแƒ•แƒฃแƒ™แƒ”แƒ—แƒ”แƒ— โ€œtodoโ€ แƒกแƒแƒฎแƒ”แƒšแƒ—แƒแƒœ, แƒแƒ›แƒ˜แƒขแƒแƒ› แƒแƒ แƒ’แƒฃแƒ›แƒ”แƒœแƒขแƒแƒ“ แƒกแƒฌแƒแƒ แƒ”แƒ“ แƒแƒ› แƒกแƒแƒฎแƒ”แƒšแƒก แƒ•แƒฌแƒ”แƒ แƒ—. แƒกแƒ—แƒแƒ แƒ˜ แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒกแƒ’แƒแƒœ แƒ˜แƒœแƒคแƒแƒ แƒ›แƒแƒชแƒ˜แƒแƒก แƒแƒ›แƒ˜แƒก แƒกแƒแƒคแƒฃแƒซแƒ•แƒ”แƒšแƒ–แƒ” แƒแƒ˜แƒฆแƒ”แƒ‘แƒก แƒ“แƒ แƒ“แƒแƒ’แƒ•แƒ˜แƒ‘แƒ แƒฃแƒœแƒ”แƒ‘แƒก แƒกแƒขแƒ แƒ˜แƒ›แƒ˜แƒก แƒคแƒแƒ แƒ›แƒ˜แƒ—. แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒก แƒ—แƒ˜แƒ—แƒแƒ”แƒฃแƒšแƒ˜ แƒœแƒแƒฌแƒ˜แƒšแƒ˜แƒกแƒ—แƒ•แƒ˜แƒก แƒชแƒแƒšแƒ™แƒ” แƒ•แƒฅแƒ›แƒœแƒ˜แƒ— แƒกแƒ”แƒšแƒ”แƒฅแƒขแƒแƒ แƒ”แƒ‘แƒก createSelector แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ˜แƒ—, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒแƒ› feature แƒกแƒ”แƒšแƒ”แƒฅแƒขแƒแƒ แƒ˜แƒกแƒ’แƒแƒœ แƒ˜แƒฆแƒ”แƒ‘แƒ”แƒœ แƒ›แƒ˜แƒก แƒ™แƒแƒœแƒ™แƒ แƒ”แƒขแƒฃแƒš แƒœแƒแƒฌแƒ˜แƒšแƒก. แƒ™แƒแƒœแƒ•แƒ”แƒœแƒ•แƒ˜แƒฃแƒ แƒแƒ“ แƒกแƒ”แƒšแƒ”แƒฅแƒขแƒแƒ แƒ”แƒ‘แƒ˜ select-แƒ˜แƒ— แƒ˜แƒฌแƒงแƒ”แƒ‘แƒ.

แƒแƒฎแƒšแƒ แƒ’แƒแƒ›แƒแƒ•แƒ˜แƒงแƒ”แƒœแƒแƒ— selectLoading app.component-แƒจแƒ˜ แƒ“แƒ แƒแƒ›แƒแƒกแƒ—แƒแƒœแƒแƒ•แƒ”, แƒ’แƒแƒ•แƒชแƒ”แƒ— แƒ”แƒฅแƒจแƒ”แƒœแƒ˜. แƒงแƒ•แƒ”แƒšแƒแƒคแƒ”แƒ แƒ˜ แƒ–แƒ”แƒ“แƒ›แƒ”แƒขแƒ˜ แƒฌแƒแƒ•แƒจแƒแƒšแƒแƒ—.

app.component.ts

/// ... other imports
import { Store } from "@ngrx/store";
import { TodoActions } from "./store/actions";
import { TodoSelectors } from "./store/selectors";

// ...
export class AppComponent implements OnInit {
  items$ = this.store.select(TodoSelectors.selectItems);
  loading$ = this.store.select(TodoSelectors.selectLoading);
  error$ = this.store.select(TodoSelectors.selectError);

  constructor(private store: Store) {}

  ngOnInit() {
    this.store.dispatch(TodoActions.getItems());
  }
}

แƒฉแƒ•แƒ”แƒœ แƒ™แƒแƒœแƒกแƒขแƒ แƒฃแƒฅแƒขแƒแƒ แƒจแƒ˜ แƒ“แƒแƒ•แƒแƒ˜แƒœแƒฏแƒ”แƒฅแƒ—แƒ”แƒ— Store, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒฌแƒ•แƒ“แƒแƒ›แƒแƒก แƒ’แƒ•แƒแƒซแƒšแƒ”แƒ•แƒก แƒกแƒ—แƒ”แƒ˜แƒ—แƒ˜แƒก แƒกแƒ”แƒšแƒ”แƒฅแƒขแƒแƒ แƒ”แƒ‘แƒกแƒ แƒ“แƒ แƒ”แƒฅแƒจแƒ”แƒœแƒ˜แƒก แƒ’แƒแƒจแƒ•แƒ”แƒ‘แƒ˜แƒก แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ”แƒ‘แƒ–แƒ”. แƒกแƒ”แƒšแƒ”แƒฅแƒขแƒแƒ แƒ”แƒ‘แƒก แƒ•แƒ˜แƒœแƒแƒฎแƒแƒ•แƒ— แƒคแƒ แƒแƒคแƒ”แƒ แƒ—แƒ˜แƒ”แƒ‘แƒ˜แƒ—, แƒ แƒแƒ›แƒšแƒ”แƒ‘แƒ˜แƒช แƒ™แƒแƒœแƒ•แƒ”แƒœแƒชแƒ˜แƒฃแƒ แƒแƒ“ $-แƒ˜แƒ— แƒ‘แƒแƒšแƒแƒ•แƒ“แƒ”แƒ‘แƒ, แƒ แƒแƒ“แƒ’แƒแƒœ แƒ˜แƒกแƒ˜แƒœแƒ˜ observable-แƒ”แƒ‘แƒก แƒฌแƒแƒ แƒ›แƒแƒแƒ“แƒ’แƒ”แƒœแƒ”แƒœ.

แƒ แƒแƒชแƒ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ แƒ˜แƒขแƒ•แƒ˜แƒ แƒ—แƒ”แƒ‘แƒ, แƒ”แƒก แƒฃแƒ™แƒ•แƒ” แƒœแƒ˜แƒจแƒœแƒแƒ•แƒก แƒ˜แƒ›แƒแƒก, แƒ แƒแƒ› แƒ›แƒแƒ›แƒฎแƒ›แƒแƒ แƒ”แƒ‘แƒ”แƒšแƒก แƒœแƒ˜แƒ•แƒ—แƒ”แƒ‘แƒ˜แƒก แƒ›แƒ˜แƒฆแƒ”แƒ‘แƒ แƒกแƒฃแƒ แƒก, แƒ›แƒแƒจแƒแƒกแƒแƒ“แƒแƒ›แƒ” แƒฉแƒ•แƒ”แƒœ แƒฃแƒœแƒ“แƒ แƒกแƒ—แƒแƒ แƒ˜แƒก แƒกแƒแƒจแƒฃแƒแƒšแƒ”แƒ‘แƒ˜แƒ— getItems แƒ”แƒฅแƒจแƒ”แƒœแƒก แƒ“แƒแƒ•แƒฃแƒซแƒแƒฎแƒแƒ—.

แƒ—แƒ”แƒ›แƒคแƒšแƒ”แƒ˜แƒ—แƒจแƒ˜ แƒจแƒ”แƒ’แƒ•แƒ˜แƒซแƒšแƒ˜แƒ observable-แƒ”แƒ‘แƒก แƒ›แƒแƒ•แƒฃแƒกแƒ›แƒ˜แƒœแƒแƒ— ngIf แƒ“แƒ˜แƒ แƒ”แƒฅแƒขแƒ˜แƒ•แƒจแƒ˜, async แƒคแƒแƒ˜แƒคแƒ˜แƒก แƒกแƒแƒจแƒฃแƒแƒšแƒ”แƒ‘แƒ˜แƒ—. แƒ”แƒก แƒคแƒแƒ˜แƒคแƒ˜ แƒแƒ•แƒขแƒแƒ›แƒแƒขแƒฃแƒ แƒแƒ“ แƒ“แƒแƒแƒกแƒฃแƒ‘แƒกแƒฅแƒ แƒแƒ˜แƒ‘แƒ”แƒ‘แƒก แƒแƒ› observable-แƒก แƒ“แƒ แƒกแƒแƒญแƒ˜แƒ แƒแƒ”แƒ‘แƒ˜แƒก แƒจแƒ”แƒ›แƒ—แƒฎแƒ•แƒ”แƒ•แƒแƒจแƒ˜ แƒกแƒฃแƒ‘แƒกแƒฅแƒ แƒแƒ˜แƒ‘แƒก แƒ’แƒแƒแƒฃแƒฅแƒ›แƒ”แƒ‘แƒก แƒ™แƒ˜แƒ“แƒ”แƒ•แƒแƒช (ts-แƒจแƒ˜ แƒแƒ›แƒ˜แƒก แƒฎแƒ”แƒšแƒ˜แƒ— แƒฌแƒ”แƒ แƒแƒก แƒคแƒแƒ˜แƒคแƒ˜ แƒœแƒแƒ›แƒ“แƒ•แƒ˜แƒšแƒแƒ“ แƒฏแƒแƒ‘แƒ˜แƒ!):

app.component.html

<div class="container">
  <app-input></app-input>
  <ng-container *ngIf="error$ | async as error">
    <h2 class="error"></h2>
  </ng-container>
  <ng-container *ngIf="items$ | async as items">
    <app-item *ngFor="let item of items" [item]="item"></app-item>
  </ng-container>
  <ng-container *ngIf="loading$ | async">
    <div class="spinner-container">
      <img src="../assets/tail-spin.svg" alt="loading spinner" />
    </div>
  </ng-container>
</div>

แƒ แƒแƒชแƒ observable แƒ แƒแƒ˜แƒ›แƒ” แƒ›แƒ˜แƒกแƒแƒฆแƒ”แƒ‘ (truethy) แƒ›แƒœแƒ˜แƒจแƒ•แƒœแƒ”แƒšแƒแƒ‘แƒแƒก แƒ›แƒ˜แƒ˜แƒฆแƒ”แƒ‘แƒก, แƒ”แƒšแƒ”แƒ›แƒ”แƒœแƒขแƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒ–แƒ”แƒช แƒ“แƒ˜แƒ แƒ”แƒฅแƒขแƒ˜แƒ•แƒ˜แƒ แƒ’แƒแƒœแƒ—แƒแƒ•แƒกแƒ”แƒ‘แƒฃแƒšแƒ˜, แƒ’แƒแƒ›แƒแƒฉแƒœแƒ“แƒ”แƒ‘แƒ. แƒ”แƒ แƒแƒ แƒ˜แƒก แƒจแƒ”แƒ›แƒ—แƒฎแƒ•แƒ”แƒ•แƒแƒจแƒ˜, แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒแƒ“, แƒจแƒ”แƒ’แƒ•แƒ˜แƒซแƒšแƒ˜แƒ as error-แƒ˜แƒก แƒกแƒแƒจแƒฃแƒแƒšแƒ”แƒ‘แƒ˜แƒ— แƒแƒ› แƒกแƒแƒ‘แƒแƒšแƒแƒ แƒ›แƒœแƒ˜แƒจแƒ•แƒœแƒ”แƒšแƒแƒ‘แƒแƒก แƒฉแƒแƒ•แƒฌแƒ•แƒ“แƒ”แƒ—, แƒ“แƒ แƒ—แƒ”แƒ›แƒคแƒšแƒ”แƒ˜แƒ—แƒจแƒ˜ แƒ’แƒแƒ›แƒแƒ•แƒกแƒแƒฎแƒแƒ—, แƒ—แƒฃแƒ™แƒ˜ แƒ แƒแƒ˜แƒ›แƒ” แƒฎแƒแƒ แƒ•แƒ”แƒ–แƒ˜ แƒ’แƒแƒ’แƒ•แƒ˜แƒฉแƒœแƒ“แƒ. แƒ˜แƒ’แƒ˜แƒ•แƒ” แƒฎแƒ“แƒ”แƒ‘แƒ items-แƒ˜แƒกแƒ แƒ“แƒ loading-แƒ˜แƒก แƒจแƒ”แƒ›แƒ—แƒฎแƒ•แƒ”แƒ•แƒแƒจแƒ˜.

แƒ‘แƒ แƒแƒฃแƒ–แƒ”แƒ แƒจแƒ˜ แƒแƒฎแƒšแƒ แƒฉแƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒ˜แƒก แƒกแƒžแƒ˜แƒœแƒ”แƒ แƒ˜ แƒฃแƒœแƒ“แƒ แƒ’แƒแƒ›แƒแƒฉแƒœแƒ“แƒ”แƒก. Redux Devtools-แƒก แƒ—แƒฃ แƒจแƒ”แƒ•แƒฎแƒ”แƒ“แƒแƒ•แƒ—, แƒ•แƒœแƒแƒฎแƒแƒ•แƒ—, แƒ แƒแƒ› แƒ’แƒแƒ˜แƒชแƒ แƒ”แƒฅแƒจแƒ”แƒœแƒ˜ โ€œ[Todo Page] Get Itemsโ€, แƒ แƒแƒ›แƒ”แƒšแƒ›แƒแƒช แƒกแƒ—แƒ”แƒ˜แƒ—แƒจแƒ˜ loading-แƒ˜แƒก แƒ›แƒœแƒ˜แƒจแƒ•แƒœแƒ”แƒšแƒแƒ‘แƒ แƒจแƒ”แƒชแƒ•แƒแƒšแƒ, แƒ˜แƒก แƒ™แƒ˜ async แƒคแƒแƒ˜แƒคแƒ˜แƒก แƒกแƒแƒจแƒฃแƒแƒšแƒ”แƒ‘แƒ˜แƒ— แƒแƒ•แƒขแƒแƒ›แƒแƒขแƒฃแƒ แƒแƒ“ แƒแƒ˜แƒกแƒแƒฎแƒ แƒฉแƒ•แƒ”แƒœแƒก แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒแƒจแƒ˜!

Effects

แƒแƒจแƒ™แƒแƒ แƒ แƒžแƒ แƒแƒ‘แƒšแƒ”แƒ›แƒ แƒ’แƒ•แƒแƒฅแƒ•แƒก: แƒœแƒ˜แƒ•แƒ—แƒ”แƒ‘แƒ˜ แƒฏแƒ”แƒ  แƒแƒ  แƒ’แƒแƒ›แƒแƒฉแƒ”แƒœแƒ˜แƒšแƒ, แƒ แƒแƒ“แƒ’แƒแƒœ แƒกแƒแƒฌแƒงแƒ˜แƒก แƒกแƒ—แƒ”แƒ˜แƒ—แƒจแƒ˜ แƒ˜แƒก แƒชแƒแƒ แƒ˜แƒ”แƒšแƒ˜แƒ, แƒฉแƒ•แƒ”แƒœ แƒ™แƒ˜ API-แƒกแƒ—แƒ•แƒ˜แƒก แƒแƒ  แƒ“แƒแƒ’แƒ•แƒ˜แƒซแƒแƒฎแƒ”แƒ‘แƒ˜แƒ, แƒ แƒแƒ› แƒ˜แƒกแƒ˜แƒœแƒ˜ แƒแƒ’แƒ•แƒ”แƒฆแƒ. แƒ›แƒแƒจ, แƒจแƒ”แƒ•แƒฅแƒ›แƒœแƒแƒ— แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜! แƒฏแƒ”แƒ  ItemsService-แƒจแƒ˜ tap แƒแƒžแƒ”แƒ แƒแƒขแƒแƒ แƒ”แƒ‘แƒ˜ แƒ“แƒ แƒ–แƒ”แƒ“แƒ›แƒ”แƒขแƒ˜ แƒชแƒ•แƒšแƒแƒ“แƒ”แƒ‘แƒ˜ แƒ›แƒแƒ•แƒแƒจแƒแƒ แƒแƒ—. แƒ˜แƒกแƒ˜แƒœแƒ˜ แƒแƒฆแƒแƒ  แƒ“แƒแƒ’แƒ•แƒญแƒ˜แƒ แƒ“แƒ”แƒ‘แƒ.

items.service.ts

import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { map } from "rxjs";
import { environment } from "src/environments/environment";
import { Item } from "./item.model";

@Injectable({ providedIn: "root" })
export class ItemsService {
  baseUrl = environment.baseUrl;

  constructor(private httpClient: HttpClient) {}

  getItems() {
    return this.httpClient.get<Item[]>(this.baseUrl);
  }

  addItem(newItemDesc: string) {
    const newItem = {
      description: newItemDesc,
      done: false,
    };
    return this.httpClient.post<Item>(this.baseUrl, newItem);
  }

  deleteItem(id: number) {
    return this.httpClient.delete(this.baseUrl + id).pipe(
      map(() => {
        return id;
      })
    );
  }

  updateItem(item: Item) {
    return this.httpClient.patch<Item>(this.baseUrl + item.id, {
      description: item.description,
      done: item.done,
    });
  }
}

แƒแƒฎแƒšแƒ แƒ™แƒ˜ แƒจแƒ”แƒ•แƒฅแƒ›แƒœแƒแƒ— แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜:

store/state/effects/todo.effects.ts

import { HttpErrorResponse } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Actions, createEffect, ofType } from "@ngrx/effects";
import { catchError, map, mergeMap, of } from "rxjs";
import { ItemsService } from "src/app/items.service";
import { TodoActions, TodoApiActions } from "../actions";

@Injectable()
export class TodoEffects {
  getItems$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(TodoActions.getItems),
      mergeMap(() =>
        this.itemsService.getItems().pipe(
          map((items) => TodoApiActions.getItemsSuccessful({ items })),
          catchError((err: HttpErrorResponse) =>
            of(
              TodoApiActions.getItemsFailed({
                error: `Failed to get items!: Server responded with: ${err.message}`,
              })
            )
          )
        )
      )
    );
  });

  constructor(private actions$: Actions, private itemsService: ItemsService) {}
}

แƒแƒ  แƒจแƒ”แƒ’แƒ”แƒจแƒ˜แƒœแƒ“แƒ”แƒ—, RxJs แƒ—แƒฅแƒ•แƒ”แƒœแƒ˜ แƒ›แƒ”แƒ’แƒแƒ‘แƒแƒ แƒ˜แƒ! แƒฉแƒ•แƒ”แƒœ แƒ•แƒฅแƒ›แƒœแƒ˜แƒ— แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜แƒก แƒ™แƒšแƒแƒกแƒก, แƒ แƒแƒ›แƒ”แƒšแƒ–แƒ”แƒช แƒฃแƒœแƒ“แƒ แƒ’แƒแƒ›แƒแƒ•แƒ˜แƒงแƒ”แƒœแƒแƒ— @injectable() แƒ“แƒ”แƒ™แƒแƒ แƒแƒขแƒแƒ แƒ˜ (แƒ แƒแƒ“แƒ’แƒแƒœ แƒ˜แƒก แƒกแƒ”แƒ แƒ•แƒ˜แƒกแƒ˜แƒ•แƒ˜แƒ— แƒ›แƒฃแƒจแƒแƒแƒ‘แƒก). แƒ™แƒšแƒแƒกแƒจแƒ˜ แƒ’แƒแƒœแƒ•แƒกแƒแƒ–แƒฆแƒ•แƒ แƒแƒ•แƒ— แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒก, แƒ แƒแƒ›แƒšแƒ”แƒ‘แƒ˜แƒช แƒคแƒแƒฅแƒขแƒแƒ‘แƒ แƒ˜แƒ•แƒแƒ“ subscription-แƒ”แƒ‘แƒ˜แƒ. แƒ˜แƒกแƒ˜แƒœแƒ˜ createEffect แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ˜แƒ— แƒ˜แƒฅแƒ›แƒœแƒ”แƒ‘แƒ. แƒฅแƒแƒšแƒ‘แƒ”แƒฅแƒจแƒ˜ แƒฉแƒ•แƒ”แƒœ แƒ•แƒแƒกแƒฃแƒ‘แƒกแƒฅแƒ แƒแƒ˜แƒ‘แƒ”แƒ‘แƒ— แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒ˜แƒก แƒกแƒขแƒ แƒ˜แƒ›แƒก, แƒ แƒแƒ›แƒ”แƒšแƒกแƒแƒช แƒกแƒ—แƒแƒ แƒ˜ แƒ’แƒ•แƒแƒฌแƒ•แƒ“แƒ˜แƒก Actions-แƒ˜แƒก แƒกแƒแƒฎแƒ˜แƒ—. แƒฉแƒ•แƒ”แƒœ แƒกแƒขแƒ แƒ˜แƒ›แƒ˜ แƒฃแƒœแƒ“แƒ แƒ’แƒแƒ•แƒคแƒ˜แƒšแƒขแƒ แƒแƒ—, แƒ แƒแƒ“แƒ’แƒแƒœ getItems$ แƒ”แƒคแƒ”แƒฅแƒขแƒ›แƒ แƒ›แƒฎแƒแƒšแƒแƒ“ แƒ”แƒ แƒ—แƒ˜ แƒ”แƒฅแƒจแƒ”แƒœแƒ–แƒ” แƒฃแƒœแƒ“แƒ แƒ›แƒแƒแƒฎแƒ“แƒ˜แƒœแƒแƒก แƒ แƒ”แƒแƒ’แƒ˜แƒ แƒ”แƒ‘แƒ - TodoActions.getItems. pipe แƒแƒžแƒ”แƒ แƒแƒขแƒแƒ แƒจแƒ˜ แƒกแƒฌแƒแƒ แƒ”แƒ“ แƒแƒ›แƒ˜แƒขแƒแƒ› แƒ•แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ— ofType แƒแƒžแƒ”แƒ แƒแƒขแƒแƒ แƒก. แƒจแƒ”แƒ›แƒ“แƒ”แƒ’, mergeMap-แƒ˜แƒก แƒกแƒแƒจแƒฃแƒแƒšแƒ”แƒ‘แƒ˜แƒ— แƒฉแƒ•แƒ”แƒœ แƒ“แƒแƒ•แƒแƒ‘แƒ แƒฃแƒœแƒ”แƒ‘แƒ— แƒกแƒ”แƒ แƒ•แƒ˜แƒกแƒ˜แƒก API-แƒกแƒ—แƒแƒœ แƒ“แƒแƒซแƒแƒฎแƒ”แƒ‘แƒแƒก, แƒกแƒแƒ“แƒแƒช แƒฉแƒ•แƒ”แƒœ แƒ’แƒ•แƒ˜แƒœแƒ“แƒ, แƒ แƒแƒ› map แƒแƒžแƒ”แƒ แƒแƒขแƒแƒ แƒ˜แƒ— แƒแƒ›แƒแƒ•แƒ˜แƒฆแƒแƒ— แƒกแƒ”แƒ แƒ•แƒ”แƒ แƒ˜แƒ“แƒแƒœ แƒ›แƒแƒกแƒฃแƒšแƒ˜ แƒžแƒแƒกแƒฃแƒฎแƒ˜ (แƒœแƒ˜แƒ•แƒ—แƒ”แƒ‘แƒ˜) แƒ“แƒ แƒ˜แƒก แƒฉแƒ•แƒ”แƒœแƒ˜ TodoApiActions-แƒ˜แƒก แƒ”แƒฅแƒจแƒ”แƒœแƒก แƒ’แƒแƒ“แƒแƒ•แƒชแƒ”แƒ—, แƒ แƒแƒ›แƒ”แƒšแƒกแƒแƒช observable-แƒ˜แƒก แƒคแƒแƒ แƒ›แƒ˜แƒ— แƒ•แƒแƒ‘แƒ แƒฃแƒœแƒ”แƒ‘แƒ—. catchError-แƒก แƒฉแƒ•แƒ”แƒœ แƒกแƒ”แƒ แƒ•แƒ˜แƒกแƒ–แƒ” แƒ“แƒแƒซแƒแƒฎแƒ”แƒ‘แƒฃแƒš pipe แƒแƒžแƒ”แƒ แƒแƒขแƒแƒ แƒจแƒ˜ map-แƒ˜แƒก แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒ•แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ—, แƒ แƒแƒ—แƒ แƒฌแƒแƒ แƒฃแƒ›แƒแƒขแƒ”แƒ‘แƒ”แƒšแƒแƒ‘แƒ˜แƒก แƒจแƒ”แƒ›แƒ—แƒฎแƒ•แƒ”แƒ•แƒแƒจแƒ˜ แƒแƒฆแƒ•แƒ แƒ˜แƒชแƒฎแƒแƒ—, แƒ แƒ แƒกแƒแƒฎแƒ˜แƒก แƒ”แƒ แƒแƒ แƒ˜ แƒ“แƒแƒ’แƒ•แƒ˜แƒ‘แƒ แƒฃแƒœแƒ แƒกแƒ”แƒ แƒ•แƒ”แƒ แƒ›แƒ. แƒ”แƒก แƒ”แƒ แƒแƒ แƒ˜ HttpErrorResponse-แƒ˜แƒก แƒขแƒ˜แƒžแƒ˜แƒกแƒแƒ แƒแƒ› แƒžแƒ แƒแƒ”แƒฅแƒขแƒ˜แƒก แƒจแƒ”แƒ›แƒ—แƒฎแƒ•แƒ”แƒ•แƒแƒจแƒ˜. แƒแƒ› แƒ”แƒ แƒแƒ แƒ˜แƒก แƒ›แƒ”แƒกแƒ˜แƒฏแƒก แƒฉแƒ•แƒ”แƒœ แƒ’แƒแƒ›แƒแƒ•แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ— แƒ”แƒฅแƒจแƒ”แƒœแƒจแƒ˜ แƒ”แƒ แƒแƒ แƒ˜แƒก แƒขแƒ”แƒฅแƒกแƒขแƒ˜แƒก แƒจแƒ”แƒกแƒแƒฅแƒ›แƒœแƒ”แƒšแƒแƒ“, แƒ แƒแƒ›แƒ”แƒšแƒกแƒแƒช แƒฉแƒ•แƒ”แƒœ of แƒแƒžแƒ”แƒ แƒแƒขแƒแƒ แƒจแƒ˜ แƒ•แƒแƒขแƒแƒ แƒ”แƒ‘แƒ—, แƒ แƒแƒ“แƒ’แƒแƒœ catchError แƒ—แƒ•แƒ˜แƒ—แƒแƒœ observable-แƒก แƒแƒ  แƒแƒ‘แƒ แƒฃแƒœแƒ”แƒ‘แƒก, แƒ แƒแƒช แƒ”แƒคแƒ”แƒฅแƒขแƒ˜แƒกแƒ—แƒ•แƒ˜แƒกแƒแƒ แƒกแƒแƒญแƒ˜แƒ แƒ. of แƒแƒžแƒ”แƒ แƒแƒขแƒแƒ แƒ˜ แƒกแƒฌแƒแƒ แƒ”แƒ“แƒแƒช observable-แƒจแƒ˜ แƒจแƒ”แƒคแƒฃแƒ—แƒฃแƒš แƒ”แƒฅแƒจแƒ”แƒœแƒก แƒ“แƒแƒ’แƒ•แƒ˜แƒ‘แƒ แƒฃแƒœแƒ”แƒ‘แƒก.

store/state/effects/index.ts

export * from "./todo.effects";

แƒแƒฎแƒšแƒ แƒ“แƒแƒ•แƒแƒ แƒ”แƒ’แƒ˜แƒกแƒขแƒ แƒ˜แƒ แƒแƒ— แƒฉแƒ•แƒ”แƒœแƒ˜ แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜ แƒ›แƒแƒ“แƒฃแƒšแƒจแƒ˜:

app.module.ts

/// ... other imports
import { StoreModule } from "@ngrx/store";
import { todoReducer } from "./store/reducers";
import { StoreDevtoolsModule } from "@ngrx/store-devtools";
import { EffectsModule } from "@ngrx/effects";
import { TodoEffects } from "./store/effects";

@NgModule({
  // ...
  imports: [
    // ...
    StoreModule.forRoot({ todo: todoReducer }),
    EffectsModule.forRoot([TodoEffects]),
    // ...
  ],
  // ...
})
export class AppModule {}

แƒจแƒ”แƒœแƒ˜แƒจแƒ•แƒœแƒ: แƒ’แƒแƒœแƒแƒ—แƒแƒ•แƒกแƒ”แƒ— แƒ”แƒคแƒ”แƒฅแƒขแƒ˜ Array-แƒจแƒ˜, แƒ แƒแƒ“แƒ’แƒแƒœ แƒ”แƒคแƒ”แƒฅแƒขแƒ˜ แƒ”แƒ แƒ—แƒ–แƒ” แƒ›แƒ”แƒขแƒ˜ แƒจแƒ”แƒ˜แƒซแƒšแƒ”แƒ‘แƒ แƒ’แƒ•แƒฅแƒแƒœแƒ“แƒ”แƒก.

แƒ‘แƒ แƒแƒฃแƒ–แƒ”แƒ แƒจแƒ˜ แƒจแƒ”แƒ•แƒ˜แƒญแƒงแƒ˜แƒขแƒแƒ—. แƒฉแƒ•แƒ”แƒœแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ”แƒ‘แƒ˜ แƒ แƒแƒ’แƒแƒ แƒช แƒ˜แƒฅแƒœแƒ แƒ’แƒแƒ›แƒแƒฉแƒœแƒ“แƒ! Redux-แƒ˜แƒก แƒ“แƒ”แƒ•แƒ—แƒฃแƒšแƒ–แƒจแƒ˜ แƒ™แƒ˜ แƒ•แƒฎแƒ”แƒ“แƒแƒ•แƒ—, แƒ แƒแƒ› โ€œ[Todo Page] Get Itemsโ€-แƒก แƒ›แƒแƒฐแƒงแƒ•แƒ โ€œ[Todo Api] Get Items Successfulโ€, แƒ แƒแƒ›แƒ”แƒšแƒ›แƒแƒช แƒกแƒ—แƒ”แƒ˜แƒ—แƒจแƒ˜ แƒ“แƒแƒ’แƒ•แƒ˜แƒ›แƒแƒขแƒ แƒแƒฎแƒแƒšแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ”แƒ‘แƒ˜, แƒฎแƒแƒšแƒ loading แƒ’แƒแƒ“แƒแƒชแƒ•แƒแƒšแƒ false-แƒ–แƒ” (แƒ แƒแƒ’แƒแƒ แƒช แƒฉแƒ•แƒ”แƒœ แƒ”แƒก แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒจแƒ˜ แƒ›แƒ˜แƒ•แƒฃแƒ—แƒ˜แƒ—แƒ”แƒ—). แƒแƒฎแƒšแƒ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ˜แƒก แƒกแƒฎแƒ•แƒ แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ”แƒ‘แƒก แƒ›แƒ˜แƒ•แƒฎแƒ”แƒ“แƒแƒ—, แƒ—แƒแƒœ แƒฃแƒ™แƒ”แƒ—แƒ”แƒกแƒ˜ แƒžแƒ แƒแƒฅแƒขแƒ˜แƒ™แƒ˜แƒก แƒžแƒแƒขแƒ”แƒ แƒœแƒ”แƒ‘แƒก แƒ›แƒ˜แƒ•แƒงแƒ•แƒ”แƒ—.

แƒฃแƒ™แƒ”แƒ—แƒ”แƒกแƒ˜ แƒžแƒแƒขแƒ”แƒ แƒœแƒ”แƒ‘แƒ˜

แƒซแƒ˜แƒ แƒ˜แƒ—แƒแƒ“แƒ˜ แƒšแƒแƒ’แƒ˜แƒ™แƒ, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒกแƒ—แƒแƒ แƒก แƒ”แƒฎแƒ”แƒ‘แƒ แƒฃแƒœแƒ“แƒ แƒ˜แƒงแƒแƒก แƒ’แƒแƒœแƒ—แƒแƒ•แƒกแƒ”แƒ‘แƒฃแƒšแƒ˜ แƒ”แƒ แƒ— แƒ™แƒแƒœแƒขแƒ”แƒ˜แƒœแƒ”แƒ  แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒจแƒ˜, แƒ›แƒแƒก แƒจแƒ˜แƒ’แƒœแƒ˜แƒ— แƒแƒ แƒกแƒ”แƒ‘แƒฃแƒšแƒ˜ แƒžแƒแƒขแƒแƒ แƒ แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ”แƒ‘แƒ˜ แƒ™แƒ˜ แƒฃแƒ‘แƒ แƒแƒšแƒแƒ“ แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ”แƒ‘แƒก แƒ˜แƒฆแƒ”แƒ‘แƒ”แƒœ แƒ–แƒ”แƒ“แƒ แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜แƒ“แƒแƒœ, แƒ›แƒแƒก แƒ—แƒ”แƒ›แƒคแƒšแƒ”แƒ˜แƒ—แƒจแƒ˜ แƒ’แƒแƒœแƒแƒ—แƒแƒ•แƒกแƒ”แƒ‘แƒ”แƒœ แƒ“แƒ แƒฃแƒ‘แƒ แƒแƒšแƒแƒ“ แƒ˜แƒ•แƒ”แƒœแƒ—แƒ”แƒ‘แƒก แƒแƒ”แƒ›แƒ˜แƒ—แƒ”แƒ‘แƒ”แƒœ. แƒแƒกแƒ”แƒ แƒแƒ› แƒ›แƒแƒ•แƒแƒจแƒแƒ แƒแƒ— แƒกแƒ”แƒ แƒ•แƒ˜แƒกแƒ”แƒ‘แƒ—แƒแƒœ แƒ“แƒแƒ™แƒแƒ•แƒจแƒ˜แƒ แƒ”แƒ‘แƒฃแƒšแƒ˜ แƒšแƒแƒ’แƒ˜แƒ™แƒ input แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜แƒ“แƒแƒœ แƒ“แƒ item แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ˜แƒ“แƒแƒœ.

input/input.component.ts

import { Component, EventEmitter, Output } from "@angular/core";

@Component({
  selector: "app-input",
  templateUrl: "./input.component.html",
  styleUrls: ["./input.component.css"],
})
export class InputComponent {
  @Output() newItem = new EventEmitter();

  onNewItem(inputElement: HTMLInputElement) {
    const newItemDesc = inputElement.value;
    if (newItemDesc) {
      this.newItem.emit(newItemDesc);
      inputElement.value = "";
    }
  }
}

item/item.component.ts

import { Component, EventEmitter, Input, Output } from "@angular/core";
import { Item } from "../item.model";

@Component({
  selector: "app-item",
  templateUrl: "./item.component.html",
  styleUrls: ["./item.component.css"],
})
export class ItemComponent {
  @Input() item: Item;
  @Output() delete = new EventEmitter<number>();
  @Output() updateItem = new EventEmitter<Item>();

  onDeleteItem() {
    this.delete.emit(this.item.id);
  }

  onItemDone() {
    this.updateItem.emit({ ...this.item, done: !this.item.done });
  }
}

แƒ™แƒแƒœแƒขแƒ”แƒ˜แƒœแƒ”แƒ  แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒจแƒ˜, แƒแƒœแƒฃ app.component.html-แƒจแƒ˜, แƒ›แƒแƒ•แƒฃแƒกแƒ›แƒ˜แƒœแƒแƒ— แƒแƒ› แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒ”แƒ‘แƒ˜แƒก แƒ˜แƒ•แƒ”แƒœแƒ—แƒ”แƒ‘แƒก:

app.component.html

<div class="container">
  <app-input (newItem)="onNewItem($event)"></app-input>
  <ng-container *ngIf="error$ | async as error">
    <h2 class="error"></h2>
  </ng-container>
  <ng-container *ngIf="items$ | async as items">
    <app-item
      *ngFor="let item of items"
      [item]="item"
      (delete)="onDelete($event)"
      (updateItem)="onUpdateItem($event)"
    ></app-item>
  </ng-container>
  <ng-container *ngIf="loading$ | async">
    <div class="spinner-container">
      <img src="../assets/tail-spin.svg" alt="loading spinner" />
    </div>
  </ng-container>
</div>

แƒ“แƒ แƒกแƒแƒ—แƒแƒœแƒแƒ“แƒ แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒ˜ แƒ’แƒแƒ•แƒชแƒ”แƒ— แƒ˜แƒ•แƒ”แƒœแƒ—แƒ”แƒ‘แƒ˜แƒก แƒ›แƒ˜แƒฎแƒ”แƒ“แƒ•แƒ˜แƒ—, แƒ แƒแƒ›แƒšแƒ”แƒ‘แƒกแƒแƒช แƒกแƒแƒ—แƒแƒœแƒแƒ“แƒ prop-แƒ”แƒ‘แƒก แƒ’แƒแƒ•แƒแƒขแƒแƒœแƒ—:

app.component.ts

import { Component, OnInit } from "@angular/core";
import { Store } from "@ngrx/store";
import { Item } from "./item.model";
import { TodoActions } from "./store/actions";
import { TodoSelectors } from "./store/selectors";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})
export class AppComponent implements OnInit {
  items$ = this.store.select(TodoSelectors.selectItems);
  loading$ = this.store.select(TodoSelectors.selectLoading);
  error$ = this.store.select(TodoSelectors.selectError);

  constructor(private store: Store) {}

  ngOnInit() {
    this.store.dispatch(TodoActions.getItems());
  }

  onNewItem(description: string) {
    this.store.dispatch(TodoActions.addItem({ description }));
  }

  onDelete(id: number) {
    this.store.dispatch(TodoActions.deleteItem({ id }));
  }

  onUpdateItem(item: Item) {
    this.store.dispatch(TodoActions.updateItem({ item }));
  }
}

แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ˜แƒก แƒ“แƒแƒœแƒแƒ แƒฉแƒ”แƒœแƒ˜ แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ”แƒ‘แƒ˜ NgRx-แƒ˜แƒ—

แƒแƒฎแƒšแƒ แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒจแƒ˜ แƒ“แƒแƒ•แƒฌแƒ”แƒ แƒแƒ— แƒ แƒ แƒฃแƒœแƒ“แƒ แƒ›แƒแƒฎแƒ“แƒ”แƒก แƒ“แƒแƒœแƒแƒ แƒฉแƒ”แƒœแƒ˜ แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒ˜แƒก แƒจแƒ”แƒ›แƒ—แƒฎแƒ•แƒ”แƒ•แƒแƒจแƒ˜:

store/reducers/todo.reducers.ts

import { createReducer, on } from "@ngrx/store";
import { TodoActions, TodoApiActions } from "../actions";
import { TodoState } from "../state";
import { TodoUtils } from "../util/todo.util";

const initialState: TodoState = {
  items: [],
  loading: false,
  error: "",
};

export const todoReducer = createReducer(
  initialState,

  // Get Items
  on(TodoActions.getItems, (state) => ({ ...state, loading: true })),
  on(TodoApiActions.getItemsSuccessful, (state, { items }) => ({
    ...state,
    items: items,
    loading: false,
  })),
  on(TodoApiActions.getItemsFailed, (state, { error }) => ({
    ...state,
    error: error,
    loading: false,
  })),

  // Add Item
  on(TodoActions.addItem, (state) => ({ ...state, loading: true })),
  on(TodoApiActions.addItemSuccessful, (state, { item }) => ({
    ...state,
    items: [item, ...state.items],
    loading: false,
  })),
  on(TodoApiActions.addItemFailed, (state, { error }) => ({
    ...state,
    error: error,
    loading: false,
  })),

  // Delete Item
  on(TodoActions.deleteItem, (state) => ({ ...state, loading: true })),
  on(TodoApiActions.deleteItemSuccessful, (state, { id }) => ({
    ...state,
    items: TodoUtils.removeItem(state.items, id),
    loading: false,
  })),
  on(TodoApiActions.deleteItemFailed, (state, { error }) => ({
    ...state,
    error: error,
    loading: false,
  })),

  // Update Item
  on(TodoActions.updateItem, (state) => ({ ...state, loading: true })),
  on(TodoApiActions.updateItemSuccessful, (state, { item }) => ({
    ...state,
    items: state.items.map((i) => {
      if (i.id === item.id) {
        return item;
      } else {
        return i;
      }
    }),
    loading: false,
  })),
  on(TodoApiActions.updateItemFailed, (state, { error }) => ({
    ...state,
    error: error,
    loading: false,
  }))
);

แƒœแƒ˜แƒ•แƒ—แƒ˜แƒก แƒฌแƒแƒจแƒšแƒ˜แƒก แƒฌแƒแƒ แƒ›แƒแƒขแƒ”แƒ‘แƒฃแƒšแƒแƒ“ แƒ“แƒแƒ›แƒ—แƒแƒ•แƒ แƒ”แƒ‘แƒ˜แƒก แƒจแƒ”แƒ›แƒ—แƒฎแƒ•แƒ”แƒ•แƒแƒจแƒ˜ แƒœแƒ˜แƒ•แƒ—แƒ˜แƒก แƒแƒ›แƒแƒกแƒแƒจแƒšแƒ”แƒšแƒแƒ“ TodoUtils-แƒจแƒ˜ แƒจแƒ”แƒฅแƒ›แƒœแƒ˜แƒš แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒแƒก แƒ•แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ—, แƒ แƒแƒ—แƒ แƒ แƒ”แƒ“แƒ˜แƒฃแƒกแƒ”แƒ แƒ˜ แƒ แƒ—แƒฃแƒšแƒ˜ แƒฌแƒแƒกแƒแƒ™แƒ˜แƒ—แƒฎแƒ˜ แƒแƒ  แƒ’แƒแƒฎแƒ“แƒ”แƒก:

store/util/todo.utils.ts

import { Item } from "src/app/item.model";

export class TodoUtils {
  public static removeItem(items: Item[], id: number) {
    const result = [...items];
    const itemindex = result.findIndex((i) => i.id === id);
    result.splice(itemindex, 1);
    return result;
  }
}

แƒ แƒ แƒ—แƒฅแƒ›แƒ แƒฃแƒœแƒ“แƒ, แƒ”แƒก แƒกแƒแƒ›แƒ˜ แƒแƒฎแƒแƒšแƒ˜ แƒ”แƒฅแƒจแƒ”แƒœแƒ˜ แƒ™แƒแƒ›แƒžแƒแƒœแƒ”แƒœแƒขแƒจแƒ˜ แƒฃแƒ‘แƒ แƒแƒšแƒแƒ“ แƒฉแƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒ˜แƒก แƒกแƒžแƒ˜แƒœแƒ”แƒ แƒก แƒ’แƒแƒ’แƒ•แƒ˜แƒฉแƒ”แƒœแƒก แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒแƒจแƒ˜, แƒ แƒแƒ“แƒ’แƒแƒœ แƒ›แƒแƒ—แƒ—แƒ•แƒ˜แƒก แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜ แƒฏแƒ”แƒ  แƒแƒ  แƒ“แƒแƒ’แƒ•แƒ˜แƒฌแƒ”แƒ แƒ˜แƒ. แƒแƒกแƒ” แƒฃแƒœแƒ“แƒ แƒ’แƒแƒ›แƒแƒ˜แƒงแƒฃแƒ แƒ”แƒ‘แƒแƒ“แƒ”แƒก แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒ˜แƒก แƒ›แƒ—แƒšแƒ˜แƒแƒœแƒ˜ แƒ™แƒแƒ“แƒ˜:

store/effects/todo.effects.ts

import { HttpErrorResponse } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Actions, createEffect, ofType } from "@ngrx/effects";
import { catchError, map, mergeMap, of } from "rxjs";
import { ItemsService } from "src/app/items.service";
import { TodoActions, TodoApiActions } from "../actions";

@Injectable()
export class TodoEffects {
  getItems$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(TodoActions.getItems),
      mergeMap(() =>
        this.itemsService.getItems().pipe(
          map((items) => TodoApiActions.getItemsSuccessful({ items })),
          catchError((err: HttpErrorResponse) =>
            of(
              TodoApiActions.getItemsFailed({
                error: `Failed to get items!: Server responded with: ${err.message}`,
              })
            )
          )
        )
      )
    );
  });

  addItem$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(TodoActions.addItem),
      mergeMap(({ description }) =>
        this.itemsService.addItem(description).pipe(
          map((item) => TodoApiActions.addItemSuccessful({ item })),
          catchError((err: HttpErrorResponse) =>
            of(
              TodoApiActions.getItemsFailed({
                error: `Failed to add item!: Server responded with: ${err.message}`,
              })
            )
          )
        )
      )
    );
  });

  deleteItem$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(TodoActions.deleteItem),
      mergeMap(({ id }) =>
        this.itemsService.deleteItem(id).pipe(
          map((id) => TodoApiActions.deleteItemSuccessful({ id })),
          catchError((err: HttpErrorResponse) =>
            of(
              TodoApiActions.getItemsFailed({
                error: `Failed to delete item!: Server responded with: ${err.message}`,
              })
            )
          )
        )
      )
    );
  });

  updateItem$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(TodoActions.updateItem),
      mergeMap(({ item }) =>
        this.itemsService.updateItem(item).pipe(
          map((item) => TodoApiActions.updateItemSuccessful({ item })),
          catchError((err: HttpErrorResponse) =>
            of(
              TodoApiActions.getItemsFailed({
                error: `Failed to update item!: Server responded with: ${err.message}`,
              })
            )
          )
        )
      )
    );
  });

  constructor(private actions$: Actions, private itemsService: ItemsService) {}
}

แƒ“แƒแƒแƒ™แƒ•แƒ˜แƒ แƒ“แƒ˜แƒ—, แƒ แƒแƒ› แƒ“แƒแƒœแƒแƒ แƒฉแƒ”แƒœ แƒ”แƒคแƒ”แƒฅแƒขแƒ”แƒ‘แƒจแƒ˜ mergeMap-แƒ˜แƒ— แƒแƒ›แƒฏแƒ”แƒ แƒแƒ“ แƒ•แƒ˜แƒฆแƒ”แƒ‘แƒ— (แƒ“แƒ”แƒกแƒขแƒ แƒฃแƒฅแƒขแƒฃแƒ แƒ˜แƒ–แƒแƒชแƒ˜แƒ˜แƒก แƒกแƒแƒจแƒฃแƒแƒšแƒ”แƒ‘แƒ˜แƒ—) แƒ”แƒฅแƒจแƒ”แƒœแƒ”แƒ‘แƒ˜แƒก prop-แƒ”แƒ‘แƒก, แƒ แƒแƒ›แƒšแƒ”แƒ‘แƒกแƒแƒช แƒกแƒ”แƒ แƒ•แƒ˜แƒกแƒก แƒ•แƒแƒฌแƒ•แƒ“แƒ˜แƒ—.

แƒฉแƒ•แƒ”แƒœแƒ˜ แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒ แƒแƒฎแƒšแƒ แƒกแƒ แƒฃแƒšแƒคแƒแƒกแƒแƒ•แƒœแƒแƒ“ แƒฃแƒœแƒ“แƒ แƒ›แƒฃแƒจแƒแƒแƒ‘แƒ“แƒ”แƒก NgRx-แƒ˜แƒ—. แƒ”แƒ แƒ—แƒ˜ แƒจแƒ”แƒฎแƒ”แƒ“แƒ•แƒ˜แƒ— แƒแƒ แƒแƒกแƒแƒญแƒ˜แƒ แƒแƒ“ แƒ‘แƒ”แƒ•แƒ แƒ˜ แƒ™แƒแƒ“แƒ˜ แƒ•แƒฌแƒ”แƒ แƒ”แƒ— แƒ“แƒ แƒ—แƒ˜แƒ—แƒฅแƒแƒก แƒจแƒ”แƒ›แƒแƒ•แƒšแƒ˜แƒ—แƒ˜ แƒ’แƒ–แƒ”แƒ‘แƒ˜ แƒ’แƒแƒ›แƒแƒ•แƒ˜แƒงแƒ”แƒœแƒ”แƒ—, แƒ›แƒแƒ’แƒ แƒแƒ› แƒ แƒแƒชแƒ แƒ“แƒ˜แƒ“ แƒ“แƒ แƒ แƒ—แƒฃแƒš แƒแƒžแƒšแƒ˜แƒ™แƒแƒชแƒ˜แƒแƒ–แƒ” แƒ•แƒ›แƒฃแƒจแƒแƒแƒ‘แƒ—, NgRx-แƒ˜แƒก แƒกแƒแƒจแƒฃแƒแƒšแƒ”แƒ‘แƒ˜แƒ— แƒ–แƒฃแƒกแƒขแƒแƒ“ แƒ•แƒ˜แƒชแƒ˜แƒ— แƒกแƒแƒ“ แƒ แƒ แƒฃแƒœแƒ“แƒ แƒ›แƒแƒฎแƒ“แƒ”แƒก แƒ“แƒ แƒ แƒแƒ’แƒแƒ , แƒ แƒแƒช แƒ“แƒ”แƒ•แƒ”แƒšแƒแƒžแƒ›แƒ”แƒœแƒขแƒ˜แƒก แƒžแƒ แƒแƒชแƒ”แƒกแƒก แƒซแƒแƒšแƒ˜แƒแƒœ แƒแƒ›แƒแƒ แƒขแƒ˜แƒ•แƒ”แƒ‘แƒก. แƒ˜แƒ’แƒ˜ แƒ’แƒ•แƒแƒ˜แƒซแƒฃแƒšแƒ”แƒ‘แƒก, แƒ แƒแƒ› แƒกแƒแƒฃแƒ™แƒ”แƒ—แƒ”แƒกแƒ แƒžแƒแƒขแƒ”แƒ แƒœแƒ”แƒ‘แƒก แƒ›แƒ˜แƒ•แƒงแƒ•แƒ”แƒ—, แƒ แƒแƒช แƒ‘แƒ”แƒ•แƒ  แƒ’แƒแƒฃแƒ—แƒ•แƒแƒšแƒ˜แƒกแƒฌแƒ˜แƒœแƒ”แƒ‘แƒ”แƒš แƒ—แƒแƒ•แƒ˜แƒก แƒขแƒ™แƒ˜แƒ•แƒ˜แƒšแƒก แƒแƒ’แƒ•แƒแƒ แƒ˜แƒ“แƒ”แƒ‘แƒก.

แƒแƒ  แƒ˜แƒคแƒ˜แƒฅแƒ แƒแƒ—, แƒ แƒแƒ› NgRx-แƒก แƒ”แƒ แƒ—แƒ˜ แƒฌแƒแƒ™แƒ˜แƒ—แƒฎแƒ•แƒ˜แƒ— แƒ“แƒแƒ”แƒฃแƒคแƒšแƒ”แƒ‘แƒ˜แƒ—. แƒกแƒแƒญแƒ˜แƒ แƒแƒ”แƒ‘แƒ˜แƒก แƒจแƒ”แƒ›แƒ—แƒฎแƒ•แƒ”แƒ•แƒแƒจแƒ˜ แƒ แƒแƒ›แƒ“แƒ”แƒœแƒ˜แƒ›แƒ”แƒฏแƒ”แƒ  แƒ’แƒแƒ“แƒแƒ˜แƒ™แƒ˜แƒ—แƒฎแƒ”แƒ— แƒ”แƒก แƒ›แƒแƒกแƒแƒšแƒ, แƒ’แƒแƒ”แƒชแƒแƒœแƒ˜แƒ— แƒแƒคแƒ˜แƒชแƒ˜แƒแƒšแƒฃแƒ  แƒ“แƒแƒ™แƒฃแƒ›แƒ”แƒœแƒขแƒแƒชแƒ˜แƒ”แƒ‘แƒก แƒ“แƒ, แƒ แƒ แƒ—แƒฅแƒ›แƒ แƒฃแƒœแƒ“แƒ, แƒ—แƒฅแƒ•แƒ”แƒœแƒ˜แƒ— แƒกแƒชแƒแƒ“แƒ”แƒ— แƒ›แƒ˜แƒกแƒ˜ แƒ’แƒแƒ›แƒแƒงแƒ”แƒœแƒ”แƒ‘แƒ.

แƒฌแƒแƒ แƒ›แƒแƒขแƒ”แƒ‘แƒ”แƒ‘แƒ˜!

แƒ™แƒแƒ“แƒ˜แƒก แƒ แƒ”แƒžแƒแƒ–แƒ˜แƒขแƒแƒ แƒ˜แƒ

แƒ“แƒแƒ™แƒฃแƒ›แƒ”แƒœแƒขแƒแƒชแƒ˜แƒ”แƒ‘แƒ˜