1. Redux là gì?
Redux là một thư viện quản lý trạng thái (state management) cho ứng dụng web, phổ biến trong các ứng dụng phát triển dựa trên JavaScript và React. Nó giúp quản lý trạng thái của ứng dụng một cách dễ dàng và hiệu quả, đồng thời giúp tạo ra một luồng dữ liệu (data flow) đơn giản và dễ theo dõi.
2. Vấn đề gặp phải

3. Nguyên lý vận hành của Redux

4. Các thành phần của Redux
Redux bao gồm 3 thành phần chính: action, store và reducer:
4.1. Action
Action đơn giản là những Event được tạo ra bằng việc sử function và gửi data từ app lên store. Data có thể được gửi bằng nhiều cách như submit form, gọi API hoặc thao tác của User. Mỗi action của Redux để có một thuộc tính type để miêu tả loại action và thuộc tính payload chứa thông tinh được gửi lên store.
Để gọi một action từ bất cứ đầu trong app, Redux sử dụng method dispatch() để gửi action tới Redux store để xử lý thay đổi state.
4.2. Reducer
Vì Redux sử dụng dispatch() để thay đổi state. Tuy nhiên method này chỉ dùng để thông báo có sự thay đổi, thực tế nó không thay đổi state, các reducer mới là thứ nắm vai trò này.
Reducer là những function lấy state hiện tại và action vừa được dispatch để trả về state mới.
4.3. Store
Store chính là trái tim của Redux. Đây là "single source of truth" nắm giữ toàn bộ state của app và cung cấp những method để thao tác với state, dispatch action, ... Mỗi action được dispatch sẽ trả về state mới cho store bằng reducer.
5. Ưu điểm/Nhược điểm
Ưu điểm
Reducer trong Redux sẽ đảm nhận vai trò thuần khiết, thế nên chúng sẽ trả về đúng kết quả nếu bạn thực hiện đúng hành động và đúng State.
Hệ thống Redux được triển khai nghiêm ngặt để các mã Code trở nên có tổ chức hơn trong ứng dụng. Điều này giúp cho các User có thể hiểu và duy trì được hệ thống dễ dàng.
Khi UI ràng buộc với thư viện React trrong nền tảng cũng đồng nghĩa rằng Redux có thể phát triển mạnh mẽ để tối ưu hiệu suất cho chính mình.
Nền tảng này sẽ hỗ trợ các nhà phát triển kiểm tra ứng dụng nhanh chóng khi cần.
Nhược điểm
Redux có rất nhiều chức năng. Đồng nghĩa với việc nó sẽ có hệ thống vận hành tương đối phức tạp.
Redux thường bị giới hạn về mặt thiết kế do nó có ít sự lựa chọn thay thế.
Dữ liệu sẽ không có chức năng Encapsulation trong Redux, vì thế vấn đề bảo mật cần được lưu ý khi sử dụng nền tảng này.
Do các State bất biến, thế nên khi chúng cập nhật, các Reducer phải trả về các State mới. Từ đó khiến cho hệ thống Redux ngốn nhiều bộ nhớ hơn bình thường.
6. Khi nào nên sử dụng Redux?
Khi ứng dụng cần quản lý nhiều state phức tạp và chúng cần tương tác với nhau, việc sử dụng Redux sẽ giúp bạn quản lý các state dễ dàng hơn
Khi nhiều component cần sử dụng chung 1 state, việc sử dụng Redux sẽ giúp các component truy cập dễ dàng hơn so với việc sử dụng props
Redux cho phép theo dõi lịch sử của các state và actions, điều này rất hữu ích cho việc debug về sau. Redux còn có extension trên Chrome tên là Redux DevTools, giúp chúng ta có thể dễ dàng theo dõi lịch sử thay đổi của state và actions ngay trên trình duyệt.
Lợi ích
Với chỉ một "Source of Truth" (store), chúng ta sẽ gặp ít vấn đề trong việc sync state giữa các component với nhau hơn.
Redux có bộ guideline hết sức chặt chẽ về cách tổ chức code, action làm gì, reducer làm việc gì,... Mọi thứ đều cụ thể và rõ ràng nên việc maintain sẽ dễ dàng hơn nhiều.
Như đã nói ở trên, với việc tổ chức code nghiêm ngặt và rõ ràng, việc scale project sẽ trở nên dễ dàng hơn nhiều.
7. Lưu ý khi sử dụng Redux?
8. Redux toolkit
RTK là một thư viện giúp mình viết Redux tốt hơn, dễ hơn và đơn giản hơn (tiêu chuẩn để viết Redux).
Ba vấn đề làm nền tảng ra đời RTK:
configureStore()
// Khi chưa có Redux Toolkit
// store.js
import { createStore, applyMiddleware, compose } from 'redux';
import thunkMiddleware from 'redux-thunk';
import rootReducer from './reducers';
// Enable to use redux dev tool in development mode
const composeEnhancers = 'development' === process.env.NODE_ENV
? (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose)
: compose;
// Use redux-thunk as a redux middleware
const enhancer = composeEnhancers(applyMiddleware(thunkMiddleware));
const store = createStore(rootReducer, {}, enhancer);
export default store;// Khi đã có redux toolkit 🤣
// store.js
import { configureStore } from '@reduxjs/toolkit'
import rootReducer from './reducers'
const store = configureStore({ reducer: rootReducer })createReducer()
// Không có Redux Toolkit
function counterReducer(state = 0, action) {
switch (action.type) {
case 'increment':
return state + action.payload
case 'decrement':
return state - action.payload
default:
return state
}
}// Có Redux Toolkit
// - Mỗi key là một case
// - Không cần handle default case
const counterReducer = createReducer(0, {
increment: (state, action) => state + action.payload,
decrement: (state, action) => state - action.payload
})// Một điểm hay nữa là reducer có thể mutate data trực tiếp.
// Bản chất bên dưới họ sử dụng thư viện Immerjs
const todoReducer = createReducer([], {
addTodo: (state, action) => {
// 1. Có thể mutate data trực tiếp 🎉
state.push(action.payload)
},
removeTodo: (state, action) => {
// 2. Hoặc phải trả về state mới
// CHỨ KO ĐƯỢC cả 1 và 2 nha 😎
const newState = [...state];
newState.splice(action.payload, 1);
return newState;
}
})
createAction()
// Không có redux toolkit
const INCREMENT = 'counter/increment'
function increment(amount) {
return {
type: INCREMENT,
payload: amount
}
}
const action = increment(3)
// { type: 'counter/increment', payload: 3 }// Có redux toolkit
const increment = createAction('counter/increment')
const action = increment(3)
// returns { type: 'counter/increment', payload: 3 }
console.log(increment.toString())
// 'counter/increment'Các bạn đọc thêm những hàm sau nữa nhé 😉
Setup một ví dụ đơn giản sử dụng RTK
// 1. Setup todo slice
// todoSlice.js
const todoSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
addPost(state, action) {
state.push(action.payload);
},
removePost(state, action) {
state.splice(action.payload, 1)
}
}
});
const { actions, reducer } = todoSlice;
export const { addPost, removePost } = actions;
export default reducer;// 2. Setup redux store
// store.js
import { configureStore } from '@reduxjs/toolkit';
import todoSlice from 'features/todos/todoSlice';
const store = configureStore({
reducer: {
todos: todoSlice
},
})// 3. Bind Redux Provider to App
// src/index.js
import { Provider } from 'react-redux';
import store from './store';
import App from './App';
function Main() {
return (
<Provider store={store}>
<App />
</Provider>
)
}// 4. Using redux in component
// todo.jsx
import { useDispatch, useSelector } from 'react-redux';
import { removeTodo } from 'features/todos/todoSlice';
import {View, TouchableOpacity, Text} from 'react-native';
function Todo() {
const dispatch = useDispatch();
const todoList = useSelector(state => state.todos);
const handleTodoClick = (todo, idx) => {
const action = removeTodo(idx);
dispatch(action);
}
return (
<View>
{todoList.map((todo, idx) => (
<TouchableOpacity key={todo.id} onPress={() => handleTodoClick(todo, idx)}>
<Text>
{todo.title}
</Text>
</TouchableOpacity>
))}
</View>
)
}Share this article