Friday, January 22, 2021
Lưu Xuân Trường's Blog
  • Trang chủ
  • Backend
    • Laravel
    • Golang
    • NodeJS
    • MongoDB
    • Redis
    • WordPress
      • Kinh nghiệm
      • Plugins
  • Frontend
    • CSS
    • Javascript
      • ReactJS
      • UmiJS
      • VueJS
      • NuxtJS
      • Angular
      • RxJS
    • Game HTML5
  • Mobile
    • React Native
    • IOS
    • Android
    • Flutter
  • Tutorials
    • Redux-Saga
  • How to
  • Góc Ngoài Lề
    • Sống Chậm Nghĩ Sâu
    • Câu Hỏi Phỏng Vấn
    • IQ Test
  • Liên Hệ
No Result
View All Result
  • Trang chủ
  • Backend
    • Laravel
    • Golang
    • NodeJS
    • MongoDB
    • Redis
    • WordPress
      • Kinh nghiệm
      • Plugins
  • Frontend
    • CSS
    • Javascript
      • ReactJS
      • UmiJS
      • VueJS
      • NuxtJS
      • Angular
      • RxJS
    • Game HTML5
  • Mobile
    • React Native
    • IOS
    • Android
    • Flutter
  • Tutorials
    • Redux-Saga
  • How to
  • Góc Ngoài Lề
    • Sống Chậm Nghĩ Sâu
    • Câu Hỏi Phỏng Vấn
    • IQ Test
  • Liên Hệ
No Result
View All Result
Lưu Xuân Trường's Blog
No Result
View All Result

Redux Saga phần II (Các khái niệm cơ bản)

truongluu by truongluu
31/10/2020
in Redux-Saga, Tutorials
Reading Time: 9min read
0 0
0
Redux Saga phần II (Các khái niệm cơ bản)
0
SHARES
291
VIEWS
Share on FacebookShare on Twitter

Phần I, chúng ta đã đi qua về cách cài đặt và sử dụng redux-saga trong ứng dụng reactJS. Bài này mình sẽ đi qua về các khái niệm cơ bản khi sử dụng redux-saga mình phải nắm được để làm việc được tốt hơn.

  • Hiệu ứng (Effects) trong redux-saga
  • Phân biệt watcher, worker trong redux-saga
  • Sử dụng 1 số effects hay dùng (takeEvery, takeLatest, take, delay…)

Hiệu ứng (Effect) trong redux-saga

Về cơ bản thì redux-saga được xây dựng dựa trên nền là Generator function. Nên việc thực thi các hàm trong redux-saga, sẽ là chạy nhiều lần, chạy -> dừng -> chạy tiếp. Các hiệu ứng trong redux-saga, bạn cứ hình dung nó là các hàm hổ trợ được redux-saga xây dựng sẵn để giúp mình thao tác khi làm việc với Generator function thuận tiện hơn, tất cả hiệu ứng nằm trong đường dẫn ‘redux-saga/effects‘. Các bạn có thể sử dụng bằng cách import vào

1
import { take, takeLatest, takeEvery, call, put, select, delay } from 'redux-saga/effects'

Các effects trong redux-saga, ngắn gọn lại theo cách hiểu đơn giản nhất là nó là những hàm hổ trợ được gói trong package redux-saga/effects. Dựa vào effect đã cung cấp mà mình có thể làm được những công việc sau trong ứng dụng

  • take: chờ đợi 1 action được gởi tới, nếu đúng hợp lệ thì sẽ qua dòng lệnh kế tiếp
  • takeLatest: nó cũng giống take là chờ đợi action gởi tới, kiểm tra có khớp với mẫu đã khai báo không. Nhưng nó không như take là chỉ chờ và chạy tiếp dòng tiếp theo, mà khi có action gởi tới khớp được, nó sẽ gởi yêu cầu này cho worker để xử lý (latest ở đây có nghĩa là gì, nếu nhiều action được gởi tới đồng thời, thì nó chỉ nhận 1 action cuối cùng và gởi action này cho worker xử lý, hủy tất cả các nhiệm vụ đã giao trước đó)
  • takeLeading: cũng tương tự takeLatest, khác với công việc là nó chỉ xử lý 1 action được gởi tới đầu tiên, các action gởi tới sau sẽ không được nhận nếu nhiệm vụ này chưa hoàn thành, nên có gởi 10 action tới 1 lúc thì cũng chỉ nhận 1 cái đầu tiên để xử lý cho xong thì mới quay lại nhận việc tiếp
  • call: gọi 1 hàm để xử lý, hàm này có thể là 1 Promise, 1 function bình thường hoặc 1 Generator function
  • select: effect này là bộ chọn cung cấp tiện ích để chúng ta thao tác với dữ liệu được chọn từ store
  • delay: cho phép delay ứng dụng lại 1 khoảng thời gian trước khi chạy đến đoạn mã tiếp theo

Cách sử dụng là thêm từ khóa yield ở phía trước mổi effect nha các bạn. Ví dụ: yield take(‘WAITING’);

Và khi xử dụng effect trong saga, mình sẽ có thêm khái niệm về blocking, và non-blocking effect (nghĩa là một hiệu ứng có làm block luồng đang chạy lại không hay là chạy đồng thời với nhiều effect khác) các bạn tham khảo thêm mô tả hiệu ứng nào blocking, non blocking nhé

Phân biệt watcher, worker trong redux-saga

Khi sử dụng redux-saga, mình sẽ đụng tới khái niệm watcher, worker. Tên của nó cũng đã mang theo cái nghĩa của nó luôn rồi. Các bạn chỉ cần hiểu đơn giản, để chạy được saga thì trong file định nghĩa các saga, mình sẽ tạo ra 1 ông là watcher (người xem hay ông chủ) và 1 ông là worker (công nhân), cả 2 ông này đều là Generator function nhé các bạn. Một watcher sẽ quản lý 1 hoặc nhiều worker nhé các bạn

Ông watcher sẽ đợi công việc được gởi tới, tương ứng với mổi việc nhận được là gì, thì sẽ giao việc lại cho ông worker mà mình quản lý làm thì giao việc cho worker (công nhân) làm việc :). Cách khai báo như thế nào, mình xem ví dụ bên dưới:

1
2
3
4
5
6
7
8
9
10
function* loginWorker() {
console.log('Tôi nhận việc nhé');
// xử lý login
console.log('Tôi đã xử lý xong')
}
 
export function* loginWatcher() {
// effect được sử dụng ở đây là takeLatest
yield takeLatest('XU_LY_LOGIN_GIUM_MINH_VOI' /* action type */, loginWorker /* công nhân nhận việc login */ );
}

Ở ví dụ trên mình có khai báo 1 watcher là loginWatcher và 1 worker là loginWorker

Nhiệm vụ của watcher ở đây là quan sát có công việc (action) nào được gởi tới với lời nhắn (type) là ‘XU_LY_LOGIN_GIUM_MINH_VOI‘, khi có action thỏa điều kiện này thì ông watcher này sẽ đưa nhiệm vụ cho ông worker để xử lý công việc login. Việc còn lại là ông worker sẽ xử lý login và làm gì đó tiếp theo 🙂

Tùy theo cách quản lý source code của mổi người, mà chúng ta có thể khai báo saga tập trung theo chức năng hoặc khai báo riêng lẻ. Ví dụ như tất cả các xử lý liên qua tới auth mình khai báo luôn cho 1 watcher xử lý, và giao nhiệm vụ xử lý cho nhiều ông worker được quản lý. Xét ví dụ sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function* loginWorker() {
console.log('Tôi nhận việc nhé');
// xử lý login
console.log('Tôi đã xử lý xong')
}
 
function* registerWorker() {
console.log('Tôi nhận việc nhé');
// xử lý register
console.log('Tôi đã xử lý xong')
}
 
function* logoutWorker() {
console.log('Tôi nhận việc nhé');
// xử lý logout
console.log('Tôi đã xử lý xong')
}
 
export function authWatcher*() {
// các effect được sử dụng ở đây là takeLatest
yield takeLatest('XU_LY_LOGIN_GIUM_MINH_VOI' /* action type */, loginWorker /* công nhân nhận việc login */ );
yield takeLatest('XU_LY_REGISTER_GIUM_MINH_VOI' /* action type */, registerWorker /* công nhân nhận việc register */ );
yield takeLatest('XU_LY_LOGOUT_GIUM_MINH_VOI' /* action type */, logoutWorker /* công nhân nhận việc logout */ );
}

Ở ví dụ trên thì 1 ông chủ là authWatcher quản lý tới 3 công nhân là loginWorker, registerWorker, logoutWorker

Tương tự, mình cũng sẽ có thêm các watcher khác như productWatcher, cartWatcher… chẳng hạn

Sử dụng 1 số effects hay dùng

Thường thì trong redux-saga các bạn sẽ hay dùng nhất là takeLatest, takeEvery, take, put, call, select. Một số khác thì có chức năng nâng cao hơn là race, cancel, fork, spawn…, mình chỉ mô tả 1 số thường gặp còn 1 số khác các bạn có thể hỏi thêm hoặc coi thêm trên official document nhé

Căn bản thì takeLatest, takeLeading nó cũng là một hàm hổ trợ wrap các hàm khác mà ra như fork, take, cancel, call. Xem mã bên dưới để hiểu được takeLatest và takeLeading là việc như thế nào

1
2
3
4
5
6
7
8
9
10
const takeLatest = (patternOrChannel, saga, ...args) => fork(function*() {
  let lastTask
  while (true) {
    const action = yield take(patternOrChannel)
    if (lastTask) {
      yield cancel(lastTask) // cancel is no-op if the task has already terminated
    }
    lastTask = yield fork(saga, ...args.concat(action))
  }
})

 takeLatest thì được xây dựng từ  fork, take, cancel

Mình giải thích cơ chế của đoạn mã, ở đây, ta có 1 hàm là takeLatest. Khi sử dụng cú pháp khai báo là 

1
yield takeLatest('ACTION_TYPE', worker1);

Thì việc này tạo ra cho ta 1 nhiệm vụ chạy nền (background task) ứng với đoạn mã là

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fork(function*() {
  let lastTask
  while (true) {
   // quan sát action gởi tới có khớp không
    const action = yield take(patternOrChannel)
    // kiếm tra nhiệm vụ trước đó đã hoàn thành chưa
    if (lastTask) {
     // nếu chưa hoàn thành thì hủy nhiệm vụ đã gọi trước
      yield cancel(lastTask) // cancel is no-op if the task has already terminated
    }
    // tạo nhiệm vụ nền để xử lý và lưu lại để cho lần kiếm tra tiếp theo
    lastTask = yield fork(saga, ...args.concat(action))
  }
})

Nhiệm vụ nền này là 1 vòng lặp liên tục theo cơ chế: lắng nghe có action gởi tới phù hợp -> kiểm tra có nhiệm vụ nền nào được tạo ra trước đó mà chưa hoàn thành ( nếu tốn tại thì hủy nhiệm vụ này) -> tạo nhiệm vụ nền xử lý tiếp

1
2
3
4
5
6
const takeLeading = (patternOrChannel, saga, ...args) => fork(function*() {
  while (true) {
    const action = yield take(patternOrChannel);
    yield call(saga, ...args.concat(action));
  }
})

takeLeading thì từ fork, take, call

Dựa vào mô tả chi tiết của 2 đoạn mã trên về hiệu ứng takeLatest và takeLeading, chúng ta có thể hiểu rõ hơn về bản chất khi làm việc với redux-saga. Về cơ bản thì takeLatest và takeLeading mới khai báo thì nó sẽ tạo ta task nền con tương ứng với hàm fork(function*() {}), và trong task nền con này nó sẽ xử lý việc lắng nghe action nào khớp và tiếp tục tạo ra nhiều nhiệm vụ con nhỏ hơn (takeLatest->fork) hoặc 1 nhiệm vụ (takeLeading – > call). Vì quá trình xử lý được loop liên tục bởi vòng lặp while(true), nên cứ mổi khí có hành động nào được gởi tới khớp thì lại bắt đầu tiến trình xử lý lại, cứ tiếp diễn liên tục trong vòng đời của ứng dụng

Tags: cancel actionENDreactJSreduxredux-observableredux-saga
Previous Post

Redux Saga phần I (Giới thiệu)

Next Post

Redux Saga phần III (Tips khi làm việc)

truongluu

truongluu

Next Post
Redux Saga phần III (Tips khi làm việc)

Redux Saga phần III (Tips khi làm việc)

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

An intelligent person is like a river, the deeper the less noise.

Quotations

About me

Field of interests: Svelte, ReactJS, Angular, VueJS, React Native, Flutter, NodeJS, MongoDB, Message Broker, WordPress, AdonisJS, NestJS, NuxtJS, Docker, Microservice, Arduino, Game HTML5. Hope to share my experiences with everybody

Recent Posts

  • Styled components trong ReactJS
  • Frontity cơ bản phần I (Tạo và chạy dự án)
  • React framework for WordPress
  • How to run bash script in NodeJS
  • Thiết lập việc ưu tiên gọi saga worker trong redux-saga

Recent Comments

  • truongluu on Giới thiệu về UmiJS P2 (Cấu trúc thư mục, cấu hình thường dùng)
  • Hung on Giới thiệu về UmiJS P2 (Cấu trúc thư mục, cấu hình thường dùng)
  • Redux Saga phần III (Tips khi làm việc) - Lưu Xuân Trường's Blog on Quản lý trạng thái tải khi dùng redux-saga
  • Redux Saga phần II (Các khái niệm cơ bản) - Lưu Xuân Trường's Blog on Cheatsheets Non Blocking, Blocking Redux Saga
  • truongluu on Giới thiệu về UmiJS P4 (Server Side Rendering)

Archives

  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • March 2020
  • February 2020
  • January 2020
  • June 2019
  • May 2019
  • April 2019
  • March 2019
  • February 2019
  • January 2019
  • November 2018
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • April 2018
  • March 2018

Categories

  • Angular
  • Arduino
  • Backend
  • Câu Hỏi Phỏng Vấn
  • CSS
  • Ebook
  • Frontend
  • Frontity
  • Góc Ngoài Lề
  • How to
  • IOS
  • IQ Test
  • Javascript
  • Kinh nghiệm
  • Kinh nghiệm làm việc
  • Máy chủ
  • MongoDB
  • NestJS
  • NodeJS
  • NuxtJS
  • Plugins
  • React Native
  • React Native
  • ReactJS
  • Redis
  • Redux-Saga
  • RxJS
  • Tutorials
  • UmiJS
  • Uncategorized
  • VueJS
  • WordPress

Friends

Phu's blog
  • Giới thiệu về UmiJS P1 (Tổng quan về umiJS)

    Giới thiệu về UmiJS P1 (Tổng quan về umiJS)

    0 shares
    Share 0 Tweet 0
  • RxJS toàn tập (P1 giới thiệu RxJS là gì)

    0 shares
    Share 0 Tweet 0
  • Giới thiệu về UmiJS P2 (Cấu trúc thư mục, cấu hình thường dùng)

    0 shares
    Share 0 Tweet 0
  • Redux Saga phần I (Giới thiệu)

    0 shares
    Share 0 Tweet 0
  • Giới thiệu về UmiJS P3 (Permission routing)

    0 shares
    Share 0 Tweet 0

About me

Lưu Xuân Trường

Field of interests: Svelte, ReactJS, Angular, VueJS, React Native, Flutter, NodeJS, MongoDB, Message Broker, WordPress, AdonisJS, NestJS, NuxtJS, Docker, Microservice, Arduino, Game HTML5. Hope to share my experiences with everybody

© 2020 https://luuxuantruong.info

No Result
View All Result
  • Trang chủ
  • Backend
    • Laravel
    • Golang
    • NodeJS
    • MongoDB
    • Redis
    • WordPress
      • Kinh nghiệm
      • Plugins
  • Frontend
    • CSS
    • Javascript
      • ReactJS
      • UmiJS
      • VueJS
      • NuxtJS
      • Angular
      • RxJS
    • Game HTML5
  • Mobile
    • React Native
    • IOS
    • Android
    • Flutter
  • Tutorials
    • Redux-Saga
  • How to
  • Góc Ngoài Lề
    • Sống Chậm Nghĩ Sâu
    • Câu Hỏi Phỏng Vấn
    • IQ Test
  • Liên Hệ

© 2020 https://luuxuantruong.info

Welcome Back!

Login to your account below

Forgotten Password?

Create New Account!

Fill the forms below to register

All fields are required. Log In

Retrieve your password

Please enter your username or email address to reset your password.

Log In