Redux Saga - thư viện middleware hiệu quả cho Redux

  1. Công nghệ thông tin

I. Giới thiệu

Chào bạn, nếu đang đọc bài viết này thì chắc hẳn bạn đã có chút kiến thức về

React native
redux
. Trong các dự án thực tế sử dụng React native, một phần rất quan trọng và gần như chắc chắn phải có đó chính là middleware.

1. Middleware là gì mà quan trọng đến vậy?

Một ứng dụng thực tế thường đòi hỏi có những thao tác xử lý cần thời gian để phản hồi ( các thao tác bất đồng bộ lấy dữ liệu từ api hay các thao tác đọc ghi file hay đọc cookie từ trình duyệt, ...). Các thao tác như vậy trong lập trình hàm gọi là side effects. Nhưng redux lại có một số ràng buộc:

  • Thứ nhất: Các xử lý trong Reducers phải là các hàm đồng bộ và pure, trả về state mới
  • Thứ hai: Reducers sẽ ko được sử dụng các hàm async vì không được thay đổi global state.

Do đó để có thể giải quyết được các side effect này ta cần thực hiện nó ở middeware.

2. Middleware trong Redux

Trong Redux, middleware là một lớp nằm giữa Reducers và Dispatch Action, nó sẽ modify và được gọi trước khi action được dispatch. Hiện nay có khá nhiều thư viện middleware cho redux nhưng nổi tiếng và được sử dụng nhiều nhất đó là redux-saga, redux-thunk và redux-observable.

Cả 3 thư viện trên đều có thể giải quyết được hầu hết các trường hợp. Mặc dù redux thunk khá dễ hiểu và dễ code nhưng nó chưa thực sự mạnh trong một số tình huống, điều này được khắc phục với các thư viện mạnh mẽ hơn như redux saga và redux observale.

Ok giờ bạn đã hiểu sự cần thiết của redux middleware để giải quyết vấn đề rồi. Trong phạm vi bài viết này tôi sẽ giới thiệu về thư viện redux saga.

II Hoạt động của Redux saga

1. Generator function

Để hiểu được sự hoạt động của redux saga bạn cần hiểu một số khái niệm cơ bản như generator function. Generator function là function có khả năng hoãn lại quá trình thực thi mà vẫn giữ nguyên được context. Hơi khó hiểu phải không, nói một cách đơn giản thì generator function là 1 function có khả năng tạm ngưng trước khi hàm kết thúc (khác với pure function khi được gọi sẽ thực thi hết các câu lệnh trong hàm), và có thể tiếp tục chạy tại một thời điểm khác. Chính chức năng mới này giúp ta giải quyết được việc bất đồng bộ, hàm sẽ dừng và đợi async chạy xong rồi tiếp tục thực thi.

2. Hoạt động

Bây giờ ta sẽ đi chi tiết vào hoạt động của redux-saga để hiểu nó làm gì để giải quyết các side effect


Redux saga cung cấp các hàm helper effect, các hàm này sẽ trả về một effect object chứa đựng thông tin đặc biệt chỉ dẫn middeware của Redux có thể thực hiện tiếp các hành động khác. Các hàm helper effect sẽ được thực thi trong các generator function.

Một số helper trong redux saga:

  1. takeEvery() : thực thi và trả lại kết quả của mọi actions được gọi.
  2. takeLastest() : có nghĩa là nếu chúng ta thực hiện một loạt các actions, nó sẽ chỉ thực thi và trả lại kết quả của của actions cuối cùng.
  3. take() : tạm dừng cho đến khi nhận được action
  4. put() : dispatch một action.
  5. call(): gọi function. Nếu nó return về một promise, tạm dừng saga cho đến khi promise được giải quyết.
  6. race() : chạy nhiều effect đồng thời, sau đó hủy tất cả nếu một trong số đó kết thúc

III Ví dụ

Chúng ta sẽ thực hiện một ví dụ để hiểu cách thực hiện redux saga trong Project. Ở đây ta sẽ thực hiện một hành động đó là lấy danh sách các bộ phim từ server. Để thực thi một Saga, trước hết chúng ta cần tạo một action. Trong file actions.js, ta thêm đoạn code sau:

import { FETCHING_FILM_LIST} from'./constants' 
export function fetchData() {
    return { type: FETCHING_FILM_LIST } 
} 
    

Chúng ta tạo một function để lấy dữ liệu film từ api và đặt nó trong file api.js

export function getFilm() {
    return fetch('https://facebook.github.io/react-native/movies.json')
               .then((response) => response.json())
               .then((result) => { return result.movies })
               .catch((error) => { console.log(error) })
} 

Chúng ta tạo file reducer có tên là app và đặt vào file reducer.js

import { FETCHING_FILM_LIST, FETCHING_FILMS_SUCCESS, FETCHING_FILMS_FAIL } from './constants' 
export default app = (state=[], action) => {
    switch(type) {
         case FETCHING_FILMS_SUCCESS:
                 return action.data
         case FETCHING_FILMS_FAIL:
                 return state
         default:
                 return state
    }
 }

Các bạn tạo một file mới saga.js và thêm vào đoạn code sau để có thể thêm một action bất đồng bộ khi action fetchData thực thi:

import { FETCHING_FILM_LIST, FETCHING_FILMS_SUCCESS, FETCHING_FILMS_FAIL } from './constants' 
import { put, takeEvery } from 'redux-saga/effects' 
import getFilms from './api' 
function* fetchFilms (action) { 
    try { 
        const data = yield getFilm() 
        yield put({ type: FETCHING_FILMS_SUCCESS, data }) 
    } catch (e) { 
        yield put({ type: FETCHING_FILMS_FAIL }) 
    }
} 

function* filmSaga () { 
        yield takeEvery(FETCHING_FILM_LIST, fetchFilms) 
} 

export default filmSaga 

Chúng ta import phương thức put và takeEvery từ redux-saga/effects. Khi chúng ta gọi phương thức put, redux saga sẽ hướng middleware tới thực thi một action. takeEvery là phương thức lắng nghe kết quả trả về của hành động FETCHING_FILM_LIST và gọi về một phương thức cakback là fetchFilms

Khi phương thức fetchFilms đc gọi, sau khi thực hiện getFilm() trả về thành công thì nó sẽ thực thi hành động FETCHING_FILMS_SUCCCESS.

Chúng ta tạo file configureStore.js để sử dụng saga middleware.

import { createStore, applyMiddleware } from 'redux' 
import app from './reducers' 
import createSagaMiddleware from 'redux-saga' 
import dataSaga from './saga' 

const sagaMiddleware = createSagaMiddleware() 
export default function configureStore() { 
       const store = createStore(app, applyMiddleware(sagaMiddleware))       sagaMiddleware.run(dataSaga) 
      return store 
} 

Những điểm chính cần lưu ý trong file này là nếu chúng ta import saga và cũng createSagaMiddleware từ thư viện redux-saga. Khi chúng ta tạo ra store, chúng ta sẽ pass mọi thứ cho sagaMiddleware mà chúng ta đã tạo ra và gọi sagaMiddleWare.run trước khi mọi thứ được lưu trữ ở store.

Chạy ứng dụng và bạn sẽ nhận được danh sách các bộ phim để có thể đẩy dữ liệu ra view.

IV Kết luận

Thông qua các lý thuyết và ví dụ cụ thể, mong các bạn đã có cái nhìn tổng quát về redux saga cũng như cơ chế hoạt động của nó. Chúc các bạn có thể áp dụng được redux saga trong các dự án thực tế của mình.

Từ khóa: 

vtcc_intern_7

,

react

,

công nghệ thông tin

Chi tiết cách cài đặt, mọi người có thể xem trên


Trả lời

Chi tiết cách cài đặt, mọi người có thể xem trên