Hiểu rõ về ‘Thunk’

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,

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

constthunkFunction=(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"exportfunctionthunkCreator(todoId){// thunkFunction is the "thunk function"returnasyncfunctionthunkFunction(dispatch, getState){const response =await client.get(`/fakeApi/todo/${todoId}`)dispatch(todosLoaded(response.todos))}}//code lambda, thunkCreator is the "thunk action creator"exportconstthunkCreator=todoId=>asyncdispatch=>{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()consteventHandler=()=>{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";exportfunctionloginAsync(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();constsubmitHandler=(data: LoginFormFields)=>{dispatch(loginAsync(data));}

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

exportfunctionuserAsync(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ý:

exportfunctionuserAsync(data: LoginFormFields){returnasync(dispatch: any, getState: any)=>{//xử lý trướclet response: AxiosResponse<Array<User>,void>=await axios.get('http://localhost:3001/user');//xử lý saureturn 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.

functioncreateThunkMiddleware(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'){returnaction(dispatch, getState, extraArgument);}// Otherwise, just continue processing this action as usualreturnnext(action);};}const thunk =createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;exportdefault 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

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ