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

Quản lý trạng thái tải của ứng dụng trong create-react-app

truongluu by truongluu
03/08/2020
in Kinh nghiệm, ReactJS, UmiJS
Reading Time: 6min read
1 0
1
Quản lý trạng thái tải của ứng dụng trong create-react-app
0
SHARES
110
VIEWS
Share on FacebookShare on Twitter

Khi sử dụng dvaJS để làm việc với các ứng dụng reactJS thì mình thấy có một điểm khá hay đó là ở từng model mình không cần phải tạo các thuộc tính để lưu trữ trạng thái tải (loading, adding, fetching…), mà dvaJS cung cấp cho mình 1 plugin là dva-loading, nếu chưa biết gì về dvaJS các bạn coi thêm hoặc official document. Xem đoạn mã bên dưới mình có một counter model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const initialState = {
  counter: 0
};
 
export default {
  namespace: 'counter',
  state: initialState,
  effects: [
    *addNumber(actions, { put }){
      yeild put({
        type: 'saveCounter',
        payload: 1
      });
    }
  ],
  reducers: [
    saveCounter(state, action) {
      return {
        ...state,
        counter: state.counter + action.payload || 1
      };
    }
  ]
}

Và ở trong component mình có thể control được việc tải của từng async action là vô cùng đơn giản, với mã

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React from 'react';
import { Button } from 'antd';
import { connect } from 'dva';
 
function App({ addingNumber, counter, dispatch }) {
  return (<>
    <h1>Counter</h1>
  <p>Current number: {counter}</p>
  <Button loading={addingNumber} onClick={() => dispatch({
    type: 'counter/addNumber'
  })}>Add number</Button>
  </>);
}
 
export default connect(({
  counter,
  loading
}) => ({
  counter: counter.counter,
  addingNumber: loading.effects['counter/addNumber']
}))(App);

Rất tiện lợi 🙂

Nhưng khi làm việc với create-react-app thì hiện tại mình thấy đang làm việc khai báo lặp đi lặp lại việc này quá nhiều. Lấy ý tưởng từ việc áp dụng dva-loading, react-wait, redux-thunk, mình có xây dựng một thư viện redux-waiters. Redux waiter là một thư viện cung cấp cho mình một middleware và một số hàm chức năng để khi làm việc các bạn hoàn toàn có thể bỏ qua việc khai báo không cần thiết về trạng thái tải trong model.

Trong thư viện mình có xử dụng thêm 2 thư viện kèm theo là redux-act để quản lý state và action hiệu quả hơn, bộ chọn reselect để tăng performace cho hàm tiện ích mình cung cấp (isWaiting, anyWaiting).

Gới thiệu và cách sử dụng redux-waiters

Redux Waiters

Waiter middleware for Redux.

1
npm install redux-waiters

Or

1
yarn add redux-waiters

Motivation

Redux Waiter middleware allows you to control all loading state of action creator when you call it.

What’s a waiters?!

Inspired from react-wait, redux-thunk. Thanks for Fatih Kadir Akın

Installation

1
npm install redux-waiters
1
yarn add redux-waiters

Then, to enable Redux Waiters, use applyMiddleware():

Using

In store

1
2
3
4
5
6
import { createStore, applyMiddleware } from 'redux';
import waiter from 'redux-waiters';
import rootReducer from './reducers/index';
 
// Note: this API requires redux@>=3.1.0
const store = createStore(rootReducer, applyMiddleware(waiter));

If you use it with redux-thunk

1
2
3
4
5
6
7
import { createStore, applyMiddleware } from 'redux';
import waiter from 'redux-waiters';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
 
// Note: this API requires redux@>=3.1.0
const store = createStore(rootReducer, applyMiddleware(&#91;waiter, thunk]));

In rootReducer file

1
2
3
4
5
6
7
import { combineReducers } from 'redux';
import { waiterReducer } from 'redux-waiters';
 
export defaut combineReducers({
...
waiter: waiterReducer
});

In example counterReducer

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import { createActionResources, createReducer } from 'redux-waiters';
import { delay } from '../helpers/utils';
 
const initialState = {
  counter: 0,
  error: false,
  errorMsg: '',
};
 
export const addNumberAction = createActionResources('add number');
export const minusNumberAction = createActionResources('minus number');
 
export default createReducer(
  {
    [addNumberAction.success]: (state) => {
      return {
        ...state,
        counter: state.counter + 1,
        error: false,
      };
    },
    [addNumberAction.error]: (state) => {
      return {
        ...state,
        error: true,
      };
    },
    [minusNumberAction.start]: (state) => {
      return {
        ...state,
        errorMsg: '',
        error: false,
      };
    },
    [minusNumberAction.success]: (state) => {
      return {
        ...state,
        counter: state.counter - 1,
      };
    },
    [minusNumberAction.error]: (state, errorMsg) => {
      return {
        ...state,
        error: true,
        errorMsg,
      };
    },
  },
  initialState,
);
 
export const addNumberCreator = () =>
  addNumberAction.waiterAction(async (dispatch) => {
    try {
      dispatch(addNumberAction.start());
      await delay(3000);
      dispatch(addNumberAction.success());
    } catch (err) {
      dispatch(addNumberAction.error());
    }
  });
 
export const minusNumberCreator = () =>
  minusNumberAction.waiterAction(async (dispatch) => {
    try {
      dispatch(minusNumberAction.start());
      await delay(3000);
      throw new Error('error occur when minus number');
    } catch (err) {
      dispatch(minusNumberAction.error(err.message));
    }
  });

Example code in your component file

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
26
27
28
29
30
31
32
33
34
35
36
import { isWaiting, anyWaiting } from 'redux-waiters';
impport { Button } from 'antd';
import { addNumberCreator, minusNumerCreator, addNumberAction, minusNumberAction } from 'reducer/counterReducer';
function App({ adding, minusing, anyLoading }) {
  return (
    &lt;>
      App Component
      Add number
      Minus number
      {anyLoading ? 'Loading...' : ''}
    
  );
}
 
const isAddingNumerSelector = isWaiting(addNumberAction.id);
const isMinusingNumerSelector = isWaiting(minusNumberAction.id);
 
const mapStateToProps = (state) => {
  const {
    waiter
  } = state;
  return {
    adding: isAddingNumerSelector(waiter),
    minusing: isMinusingNumerSelector(waiter),
    anyLoading: anyWaiting(waiter)
  };
};
 
const mapDispatchToProps = (dispatch) => {
  return {
    addNumber: () => dispatch(addNumberCreator()),
    minusNumber: () => dispatch(minusNumberCreator())
  };
};
 
export default connect(mapStateToProps, mapDispatchToProps)(App);

Injecting a Custom Argument

It’s the same as redux-thunk, redux-waiters supports injecting a custom argument using the withExtraArgument function:

1
2
3
4
5
6
7
8
9
10
const store = createStore(
  reducer,
  applyMiddleware(waiter.withExtraArgument(api)),
);
 
// later
const fetchUser = (id) =>
  fetchUserAction.waiterAction(async (dispatch, getState, api) => {
    // you can use api here
  });

To pass multiple things, just wrap them in a single object. Using ES2015 shorthand property names can make this more concise.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const api = 'http://www.example.com/sandwiches/';
const whatever = 42;
 
const store = createStore(
  reducer,
  applyMiddleware(waiter.withExtraArgument({ api, whatever })),
);
 
// later
const fetchUserCreator = (id) =>
  fetchUserAction.waiterAction(
    async (dispatch, getState, { api, whatever }) => {
      try {
        dispatch(fetchUserAction.start());
        dispatch(fetchUserAction.success());
      } catch (err) {
        dispatch(fetchUserAction.error());
      }
    },
  );

Template mẫu: https://github.com/truongluu/redux-waiters-example

Happy coding 🙂

Tags: dva-loadingdvaJSreact-waitredux-actredux-thunkredux-waitersreselect
Previous Post

Chia sẻ một số câu hỏi phỏng vấn về kiến thức nền tảng trong Javascript

Next Post

Quản lý trạng thái tải khi dùng redux-saga

truongluu

truongluu

Next Post
Quản lý trạng thái tải khi dùng redux-saga

Quản lý trạng thái tải khi dùng redux-saga

Comments 1

  1. Pingback: Quản lý trạng thái tải khi dùng redux-saga - Lưu Xuân Trường's Blog

Leave a Reply Cancel reply

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

Life is a journey, not a destination

Ralph Waldo Emerson

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