Watcher Effect Trong DvaJS

Trong DvaJS có 1 tính năng khá hay mà chắc ai cũng dùng tới hoặc sẽ có lúc cần sử dụng đó là theo dõi, được chia làm 2 loại.

  1. Theo dõi thay đổi từ đường dẫn của ứng dụng (history.listen)
  2. Theo dõi hiệu ứng (Effects)

I. Theo dõi sự thay đổi từ đường dẫn của ứng dụng:

Được sử dụng khi nào. Ví dụ trong trường hợp, ví dụ bạn cần xử lý là khi vào trang chi tiết sản phẩm với path là /product/id-san-pham thì sẽ fetch lấy dữ liệu chi tiết sản phẩm về, cập nhập lại vào state của product.

Ví dụ, mình có 1 state product có mã như bên dưới:

import * as productServices from '@/services/product';

export default {
  namespace: 'product',

  state: {
    currentProduct: {}
  },

  effects: {
    *fetchDetail({ productId }, { call, put }) {
      const response = yield call(productServices.fetchDetail, productId);
      yield put({
        type: 'saveDetail',
        data: response.data
      });
    }
  },
  reducers: {
    saveDetail(state, action) {
      return {
        ...state,
        currentProduct: action.data
      };
    }
  }
}

Trong model product của DvaJS, có hổ trợ cho mình đăng ký lắng nghe sự kiện từ subscriptions, nếu vào trang chi tiết sản phẩm, ứng với đường dẫn /product/product-id thì mình sẽ fetch dữ liệu chi tiết sản phẩm từ server về.

subscriptions: {
    listenFetchDetail({ dispatch, history }) {
      return history.listen(({ pathname }) => {
        const match = pathToRegexp('/product/:productId').exec(pathname);
        if (match) {
          dispatch({
            type: 'fetchDetail',
            productId: match[1]
          })
        }
      });
    }
  }

Ở đoạn mã trên, bằng cách tạo key và hàm trong subscriptions, chúng ta sẽ đăng ký lắng nghe sự thay đổi từ history, nếu pathname hiện tại là đường dẫn của chi tiết sản phẩm (product/product-id), thì sẽ fetch dữ liệu từ server về.

II. Theo dõi hiệu ứng (Effects):

Với cách này, chúng ta có thể làm được nhiều việc hơn là lắng nghe thay đổi từ pathname. Xét một kịch bản như sau:

Khi user login vào hệ thống, chúng ta sẽ lắng nghe, nếu đã login vào hệ thống và có thông tin user (effect là user/login/@@end), chúng ta sẽ yêu cầu lấy vị trí hiện tại của người dùng trên trình duyệt (Geolocation_API). Model user như sau:

import * as userServices from '@/services/user';

export default {
  namespace: 'user',

  state: {
    user: {},
    currentLocation: {}
  },

  effects: {
    *login({ username, password }, { call, put }) {
      const response = yield call(userServices.login, { username, password });
      if (response) {
        yield put({
          type: 'saveUser',
          data: response.data
        });
      }
    }
  },
  reducers: {
    saveUser(state, action) {
      return {
        ...state,
        user: action.data
      };
    },
    saveCurrentLocation(state, action) {
      return {
        ...state,
        currentLocation: action.data
      };
    }
  }
}

để lắng nghe Effects trong dvaJS, API cung cấp cho ta một khái niệm là watcher effect, ta khai báo thêm trong user model như sau:

import * as userServices from '@/services/user';
import { getGeoMe } from '@/utils/maps';

export default {
  namespace: 'user',

  state: {
    user: {},
    currentLocation: {}
  },

  effects: {
    *login({ username, password }, { call, put }) {
      const response = yield call(userServices.login, { username, password });
      if (response) {
        yield put({
          type: 'saveUser',
          data: response.data
        });
      }
    },
    loginWatcher: [
      function*({ take, select, call, put }) {
        while (true) {
          yield take('user/login/@@end');
          const currentLocation = yield call(getGeoMe);
          yield put({
            type: 'saveCurrentLocation',
            data: currentLocation.location
          });
        }
      },
      {
        type: 'watcher'
      }
    ]
  },
  reducers: {
    saveUser(state, action) {
      return {
        ...state,
        user: action.data
      };
    },
    saveCurrentLocation(state, action) {
      return {
        ...state,
        currentLocation: action.data
      };
    }
  }
}

Khác với việc sử dụng theo dõi từ thay đổi của pathname ứng dụng, thì theo dõi Effects chạy xuyên suốt trong ứng dụng, lúc ứng dụng được chạy và nạp model, mổi lần có effects login user được gọi và kết thúc thì nó sẽ bắt được effect này, có thể mới bắt đầu gọi tới login (user/login/@@start) hoặc đã login xong lưu dữ liệu user thành công (user/login/@@end). Trong trường hợp này ta cần bắt effect (user/login/@@end) vì lúc này user model mới có dữ liệu trong state.

Rate this post

You May Also Like

About the Author: truongluu

1 Comment

Leave a Reply

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