- vừa được xem lúc

Hiểu rõ về 'Thunk'

0 0 8

Người đăng: vĩnh đặng văn

Theo Viblo Asia

What is a ‘thunk’

Đó là một tên đặc biệt cho một function được return bởi một function khác

Thunks là các hàm được trả về ở đâu đó trong phần thân của một hàm khác.
=> nếu 1 hàm có phần return là 1 function thì function đó gọi là thunk

Đối với Redux, thunk là 1 function có logic bên trong tương tác với [dispatch][getState] của Redux
Việc sử dụng thunks yêu cầu redux-thunk, tuy nhiên Redux tool kit đã tích hợp sẵn thunk cho nên ta không cần làm gì cả

cách viết

Hàm thunk có 2 đối số: dispatch và getState

const thunkFunction = (dispatch, getState) => { alert('that is thunk function!');
}

trong đó:

  • [getState] dùng để truy cập data có trong store.
  • [dispatch] dùng để thay đổi data trong store

Vì là một tên đặc biệt cho một function được return bởi một function khác, nên cái "function" được gọi là "thunk function" và "function khác" được gọi là "thunk action creator".
Cả 2 function thì có thể là function hoặc là hàm lambda đều được:

// thunkCreator is the "thunk action creator"
export function thunkCreator(todoId) { // thunkFunction is the "thunk function" return async function thunkFunction(dispatch, getState) { const response = await client.get(`/fakeApi/todo/${todoId}`) dispatch(todosLoaded(response.todos)) }
}
//code lambda, thunkCreator is the "thunk action creator"
export const thunkCreator = todoId => async dispatch => { const response = await client.get(`/fakeApi/todo/${todoId}`) dispatch(todosLoaded(response.todos))
}

Như vậy "thunk action creator" sẽ trả về "thunk function"

Hàm thunk không được gọi trực tiếp bằng code. Thay vào đó, chúng được chuyển đến store.dispatch():

store.dispatch(thunkFunction)

và cách call "thunk function" này thì ta sẽ phải dùng store.dispatch(thunkFunction), nên code sẽ như này:

const Component: React.FC = () => { const dispatch = useDispatch() const eventHandler = () => { dispatch(thunkCreator(todoId)) //....

Mặc dù thường được sử dụng để tìm nạp dữ liệu. Tuy nhiên, chúng có thể được sử dụng cho nhiều tác vụ khác nhau và có thể chứa cả logic đồng bộ và không đồng bộ và có thể gọi dispatch hoặc getState bất kỳ lúc nào.

thực chiến:

Lưu ý, bài viết này là mục số 4 trong tìm hiểu React Redux. Nó yêu cầu bạn đã đọc trước (hiểu biết cơ bản) về Redux Core, Redux Tool Kit, React-Redux.
Nguyên nhân là từ mục 4 hất về sau thuộc tìm hiểu nguyên nhân chạy chứ không phải tìm cách chạy

Kiểm tra hoạt động với setTimeout và lấy data trong store:

tách thunk ra 1 file mới (Thunk.ts chẳng hạn):
trong File này ta sẽ sử dụng setTimeout và cũng đọc data có trong Redux thử xem

import { AnyAction, Dispatch } from "@reduxjs/toolkit";
import { LoginFormFields } from "../../features/authentication/login/function";
import { login } from "../../services/authentication/AuthenticationSlice";
export function loginAsync(data: LoginFormFields) { return (dispatch: Dispatch<AnyAction>, getState: any) => { setTimeout(() => { const state: RootState = getState(); dispatch(login(data.id)); console.log(data); console.log(state); }, 1000); };
}

tại file này, [data: LoginFormFields] được đưa vào từ thunk creator và không cần khai báo trong thunk function mà sử dụng được luôn
như mình đã nói, Hàm thunk có 2 đối số: dispatchgetState, chúng nó đều là function
dùng cái nào khì khai báo vào thì khai báo vào input, không thì không cần cho vào
function getState trả về Object store là Store tổng, nên xem data thì lại phải store.dataInside
theo vì store là mutable nên đọc lại data cũ sẽ không có cập nhật kể cả đã dispatch data mới, muốn xem cập nhật thì phải đọc lại:

const before: RootState = getState();
dispatch(login(data.id));
const after: RootState = getState();

Thực hiện dispatch data nhưng thông qua Thunk function:

import { useAppDispatch } from "../../../redux/store";
import { loginAsync } from "../../../shared/utils/Thunk";
import { LoginFormFields } from "./function";
const dispatch = useAppDispatch();
const submitHandler = (data: LoginFormFields) => { dispatch(loginAsync(data));
}

Kiểm tra hoạt động với các logic không đồng bộ async/await:

export function userAsync(data: LoginFormFields) { return (dispatch: any, getState: any) => { return axios.get('http://localhost:3001/user').then( (response: AxiosResponse<Array<User>, void>) => response.data ) };
}

hiện tại mình đang trả về 1 Promise, cho nên bên code có thể dùng Promise.then(data => handler) để xử lý
hoặc có sẵn getStatedispatch thì lấy để update vào store nếu muốn

chỗ này có thể có logic xử lý (trước/sau) khi call axios, khi đó hãy để function là async/await rồi xử lý:

export function userAsync(data: LoginFormFields) { return async(dispatch: any, getState: any) => { //xử lý trước let response: AxiosResponse<Array<User>, void> = await axios.get('http://localhost:3001/user'); //xử lý sau return response.data; };
}

Dispatch data trong Component

const userList: Promise<Array<User>> = dispatch(userAsync(data));
userList.then(data => console.log(data));

Các trường hợp sử dụng

Bởi vì thunks là một công cụ có mục đích chung có thể chứa logic tùy ý, nên chúng có thể được sử dụng cho nhiều mục đích khác nhau.
Các trường hợp sử dụng phổ biến nhất là:

  • Thực thi logic bổ sung khi bất kỳ action nào được gửi đi (chẳng hạn như ghi nhật ký hành động và trạng thái)
  • Thực hiện các request không đồng bộ hoặc logic không đồng bộ đơn giản đến vừa phải (Promises và async/await)
  • Tạm dừng, sửa đổi, trì hoãn, thay thế hoặc tạm dừng các hành động đã gửi
  • Viết logic cần gửi nhiều request liên tiếp hoặc theo thời gian (setTimeOut / setInterval)
  • Viết logic cần truy cập getState để đưa ra quyết định trong một action nào đó
  • Dạy dispatch cách chấp nhận các giá trị khác bên cạnh các plain object, chẳng hạn như các function và Promise

Thunks được sử dụng tốt nhất cho logic đồng bộ phức tạp và logic không đồng bộ đơn giản đến vừa phải, chẳng hạn như tạo một request AJAX và gửi các action dựa trên kết quả của AJAX.

middleware hoạt động thế nào

về cơ bản, mỗi khi dispatch một giá trị lên store, middleware sẽ kiểm tra xem nó có phải là 1 function hay không. Nếu không phải, cho gọi tới dispatch như bình thường. Nếu phải, nó sẽ thực hiện function đó, đợi kết quả trả về rồi dispatch giá trị trả về đó vào store.

function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { This gets called for every action you dispatch. // If it's a function, call it. if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } // Otherwise, just continue processing this action as usual return next(action); };
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;

Tổng kết

  • Thunk là function mà được trả về từ 1 function khác, function khác đó được gọi là thunk action creator
  • sử dụng thunk cho phép redux hiểu và xử lý được với các dạng trả về khác không chỉ giới hạn tại plain object
  • vì RTK cài đặt mặc định thunk và phát triển Query và Mutation cho nên vanilla thunk không còn xuất hiện nhiều nữa

Bình luận

Bài viết tương tự

- vừa được xem lúc

Những điều cần lưu ý và sử dụng Hook trong React (Phần 5)

V. Sử dụng useRef như thế nào cho đúng.

0 0 127

- vừa được xem lúc

7 Cách viết code React "clean" hơn

Mở đầu. Là nhà phát triển React, tất cả chúng ta đều muốn viết code sạch hơn, đơn giản hơn và dễ đọc hơn. 1. Sử dụng JSX shorthands.

0 0 188

- vừa được xem lúc

Create app covid-19 use Reactjs

Chào các bạn hôm nay mình sẽ chia sẻ với các bạn một app covid-19, để mọi người cùng tham khảo, tính năng của App này chỉ đơn giản là show số liệu về dịch Covid của các nước trên thế giới như: Số ngườ

0 0 39

- vừa được xem lúc

ReactJS Custom Hooks

ReactJS cung cấp rất nhiều cho bạn các hook mà bạn có thể sử dụng hằng ngày vào project của mình. Nhưng bên cạnh đó bạn có thể tự tạo ra các hook của riêng bạn để sử dụng, làm cho việc tối ưu hóa code

0 0 65

- vừa được xem lúc

3 cách để tránh re-render khi dùng React context

3 cách để tránh re-render khi dùng React context. Nếu đã từng sử dụng React context cho dự án của bạn, và gặp phải tình trạng các component con - Consumer re-render rất nhiều lần, thậm chí bị sai logi

0 0 25

- vừa được xem lúc

Tìm hiểu về React Hook: Sử dụng useDebugValue

Trong bài viết hôm này, tôi sẽ giới thiệu các bạn một React Hook tiếp theo, đó là useDebugValue. useDebugValue là gì .

0 0 45