Hướng dẫn sử dụng Redux Thunk Hooks kết hợp cùng React Hooks API

Chào mọi người, trong bài viết này mình sẽ hướng dẫn bạn cách sử dụng Redux Thunk tích hợp cùng React Hooks API .
Để bạn học ReactJS thuận tiện hơn thì mình sẽ làm những ví dụ nhỏ để bạn nắm rõ hơn về những kỹ thuật giải quyết và xử lý và tích hợp với 1 số ít library thường được sử dụng .

Khởi tạo project và cài package

Đầu tiên là chúng ta tạo một project mới bằng lệnh yarn create react-app redux-thunk-hooks

Sau khi đã tạo xong thì bạn truy cập vào project bằng lệnh cd redux-thunk-hooks và tiến hành cài 3 package redux, react-redux, redux-thunk bằng lệnh

yarn add redux react-redux redux-thunk

Sau đó thì cài thêm redux-logger bằng lệnh yarn add redux-logger --dev để chỉ cài cho môi trường dev thôi.

Sau khi add xong thì file package.json của bạn sẽ trông thế này

{
  "name": "with-redux-thunk",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-redux": "^7.2.1",
    "react-scripts": "3.4.3",
    "redux": "^4.0.5",
    "redux-thunk": "^2.3.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "redux-logger": "^3.0.6"
  }
}

Các bạn chú ý quan tâm về phiên bản của Redux thì từ bản 7.1 trở lên thì mới tương hỗ Hooks nha .

Thêm Redux vào project

Tiếp theo các bạn tạo một thư mục src/redux, src/redux/reducers, src/redux/actions, src/redux/constants và một file src/redux/store.js

Trong ví dụ lần này mình sẽ tạo một project để show một list posts get từ api về .

Sau đó tạo các file bên trong các thư mục lần lượt actions/postAction.js, reducers/postReducer.js, constants/post.js

Sau khi hoàn tất thì cấu trúc project sẽ như sau :
Folder StructureFolder Structure

Chúng ta sẽ tạo những action name ở trong file constant như sau

// post.js
export const FETCH_POST_REQUEST = "FETCH_POST_REQUEST";
export const FETCH_POST_SUCCESS = "FETCH_POST_SUCCESS";
export const FETCH_POST_ERROR = "FETCH_POST_ERROR";

Chúng ta mở file postReducer.js ra

// import constants
import {
    FETCH_POST_REQUEST,
    FETCH_POST_SUCCESS,
    FETCH_POST_ERROR,
} from '../constants/post';

// khởi tạo một init state
const initialState = {
    requesting: false,
    success: false,
    message: null,
    data: null
}

// bắt từng action type
function exampleReducers(state = initialState, payload) {
    switch (payload.type) {
        case FETCH_EXAMPLE_REQUEST:
            return {
                ...state,
                requesting: true
            };
        case FETCH_EXAMPLE_SUCCESS:
            return {
                ...state,
                requesting: false,
                success: true,
                data: payload.data
            };
        case FETCH_EXAMPLE_ERROR:
            return {
                ...state,
                requesting: false,
                message: payload.message
            };

        default:
            return state;
    }
}

export default exampleReducers;

Tiếp theo tất cả chúng ta viết action

Chúng ta dispatch với type FETCH_POST_REQUEST sau đó call api

Khi api đã call xong thì lại dispatch đến FETCH_POST_SUCCESS và kèm theo data responseBody

Trường hợp lỗi thì nó sẽ tự chạy vào catch và sẽ dispatch đến FETCH_POST_ERROR

// postAction.js
import {
    FETCH_POST_REQUEST,
    FETCH_POST_SUCCESS,
    FETCH_POST_ERROR,
} from '../constants/POST';

export const loadPosts = () => async dispatch => {
    try {
        dispatch({ type: FETCH_POST_REQUEST });

        const url = "https://jsonplaceholder.typicode.com/posts";
        const response = await fetch(url)
        const responseBody = await response.json();
        dispatch({
            type: FETCH_POST_SUCCESS,
            data: responseBody
        });
    } catch (error) {
        console.error(error);
        dispatch({
            type: FETCH_POST_ERROR,
            message: error
        });
    }
}

Sau đó sẽ tạo một file reducers/index.js để làm main reducers

// reducers/index.jsjs
import { combineReducers } from 'redux';
import postReducer from './postReducer';

const reducers = combineReducers({
	posts: postReducer,
});

export default (state, action) => reducers(state, action);

Tiếp theo tất cả chúng ta cùng viết store, về triết lý của store mình sẽ không nói lại ở đây nữa nhé .

import { createStore, applyMiddleware } from 'redux'
import { createLogger } from 'redux-logger'
import thunk from 'redux-thunk'
import reducer from './reducers'

const middleware = [ thunk ];
// check nếu không phải production thì push logger vào để log ra những action
if (process.env.NODE_ENV !== 'production') {
  middleware.push(createLogger());
}

export const store = createStore(
  reducer,
  applyMiddleware(...middleware)
)

Kết nối redux vào app

Sau khi đã xong phần redux thì bạn hãy mở file App.js lên và import 2 thằng

import { useDispatch, useSelector } from 'react-redux';
import { loadPosts } from './redux/actions/postAction';

Tiếp tục trong phần app function chúng ta viết một hàm useEffect và đồng thời khai báo useDispatch để sử dụng

Chi tiết bạn hoàn toàn có thể xem về react redux hooks

const dispatch = useDispatch();
  useEffect(() => {
    dispatch(loadPosts());
  }, [dispatch]);

Bạn vẫn gọi dispatch như bình thường, nhưng với hooks thì bạn sẽ sử dụng useDispatch để kết nói với redux.

Còn với useEffect nó sẽ chạy mỗi khi update, nó sẽ tương ứng với các hàm cũ componentDidMount, componentDidUpdate, componentWillUnmount

Tiếp theo chúng ta sẽ gọi hook useSelector ra để lấy state tương tự việc bạn mapState

Chi tiết về nó bạn hoàn toàn có thể xem tại đây

const data = useSelector((state) => state.posts.data);
  const requesting = useSelector((state) => state.posts.requesting);

Tất cả đã xong mình chuyển xuống dưới để show data ra như sau

return (
    
{ requesting ? logo : (data && data.length > 0) ?
    {data.map(item =>
  • {item.title}
  • )}
:
Data is empty
}
);

Toàn bộ file App.js của mình sẽ như thế này

import React, { useEffect } from 'react';
import logo from './logo.svg';
import './App.css';
import { useDispatch, useSelector } from 'react-redux';
import { loadPosts } from './redux/actions/postAction';

function App() {
  const data = useSelector((state) => state.post.data);
  const requesting = useSelector((state) => state.post.requesting);

  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(loadPosts());
  }, [dispatch]);

  return (
    
{ requesting ? logo : (data && data.length > 0) ?
    {data.map(item =>
  • {item.title}
  • )}
:
Data is empty
}
); } export default App;

Ok giờ chạy thử thôi yarn start và mở cổng 300 ra xem nó ra cái gì nào

Redux thunk hooks resultRedux thunk hooks result

Vậy là ok không có lỗi lầm gì cả rồi nhé.

Kết luận

Như vậy qua bài này mình đã hướng dẫn bạn sử dụng Redux Thunk Hooks. Nó không có gì khác nhiều so với sử dụng thông thường, chỉ cần thay một số ít chỗ là ok
Nếu có bất kể vướng mắc nào bạn hoàn toàn có thể comment ở bên dưới, hoặc join group Facebook để cùng luận bàn nhé

Hẹn gặp bạn trong những bài tiếp theo .