You are on page 1of 15

9

REACT REDUX

Trong chương 6, chúng ta đã biết State là một trong những dạng dữ

liệu quan trọng trong dự án React Native. State giống như một kho

lưu trữ dữ liệu cho các component trong ReactJS. Nó được sử dụng

để cập nhật component khi người dùng thực hiện một số hành động

như nhấp vào nút, nhập văn bản, ẩn hiện view nào đó,v.v...

Hiện tại chúng ta mới biết cách khai báo và sử dụng state trực tiếp

ngay trong từng component, thông qua sử dụng useState hook. Với

cách làm này thì không có gì sai và mọi người cũng vẫn đang làm như

vậy.

Tuy nhiên, nếu state đó được sử dụng ở nhiều component khác

nhau, nhiều màn hình trong ứng dụng cùng dùng chung một state.

Lúc này bạn phải làm sao?

Mình lấy ví dụ điển hình đó là trường hợp bạn cần lưu trạng thái đăng

nhập của một tài khoản. Trạng thái đăng nhập sẽ ảnh hưởng tới toàn

VNTALKING.COM 133
bộ các màn hình trong ứng dụng, bạn có thể hiểu nó như một dữ liệu

global cho toàn ứng dụng vậy.

Tiếp tục nhé! Vấn đề bắt đầu khó khăn hơn khi ứng dụng ngày càng

có nhiều state dạng global như vậy. Nào là trạng thái đăng nhập,

theme (dark mode, light mode), các cấu hình chung của ứng

dụng,v.v... Chúng ta cần phải có một giải pháp để quản lý các state

global này. Trong React Native, giải pháp phổ biến nhất là sử dụng

Redux.

Khái niệm chung Redux

Redux là một công cụ quản lý state. Mặc dù nó được sử dụng nhiều

với React. Nên nhiều người nhầm tưởng Redux là thư viện dành riêng

cho React. Nhưng thực tế thì nó có thể được sử dụng với bất kỳ

framework hoặc thư viện JavaScript nào khác.

Với Redux, các state của ứng dụng được giữ trong một "store" và các

component đều có thể truy cập vào store này để lấy state.

Về cơ bản thì Redux được xây dựng có nhiều điểm chung với Flux của

Facebook.

Redux được ra đời từ việc lấy cảm hứng từ kiến trúc Flux của

Facebook. Tuy nhiên, cách tiếp cận của Redux lại hơi khác Flux một

chút. Để rõ hơn phần này, chúng ta cùng xem nguyên lý hoạt động cơ

bản của Redux nhé.

VNTALKING.COM 134
Nguyên lý hoạt động Redux

Để sử dụng Redux dễ dàng hơn, chúng ta cần phải “thông suốt” được

3 nguyên lý chính của Redux:

• Single store: Nguyên tắc đầu tiên của Redux là tất cả các state

được chứa trong một store duy nhất, store này thường là một

Object.

• Immutable: State của ứng dụng là bất biến (Immutable). Điều

này có nghĩa là Object để lưu trữ state không cho phép chỉnh

sửa, cập nhật dữ liệu trực tiếp từ bất kỳ component nào. Để cập

nhật state trong store từ các component, chúng ta bắt buộc

phải tuân theo quy trình của Redux, đó là gửi các actions và để

các reducer function cập nhật state.

• Pure functions: Tất cả các functions để cập nhật hay tạo mới

state (Redux gọi các function này là reducer) phải là các pure

function. Mình hiểu đơn giản pure function là một hàm mà khi

các params đầu vào không thay đổi thì kết quả return luôn luôn

không thay đổi, dù hàm đó có thực thi bao nhiêu lần đi chăng

nữa.

Các thành phần của React Redux

Từ những nguyên lý trên, chúng ta bắt đầu tìm hiểu cụ thể trong

Redux có những thành phần gì? vai trò và nhiệm vụ của chúng như

nào.

VNTALKING.COM 135
Hình dưới đây minh họa cho toàn bộ cơ chế hoạt động của Redux:

Mình sẽ giải thích chi tiết hơn các thành phần trong hình trên:

“Store” có nhiệm vụ lưu trữ toàn bộ state của ứng dụng, nó được tạo

thông qua các reducer.

Để tạo store, chúng ta sử dụng hàm createStore(). Ví dụ như đoạn mã

dưới đây:

// Khởi tạo store


const store = createStore(loggeduser);

Chúng ta chỉ nên tạo duy nhất một store để dùng chung cho toàn

ứng dụng thôi nhé.

“Actions” thực chất là đối tượng Javascript được gửi đi bằng phương

thức dispatch() của React Native. Những actions này bắt buộc phải có

thuộc tính type để xác định loại action được thực hiện.

VNTALKING.COM 136
Giá trị của thuộc tính type là duy nhất, tương ứng với

action đó. Bạn không nên để trùng nhau vì sau này sẽ phát

sinh nhiều lỗi rất khó chịu. Kiểu như dispatch() một action

mà ứng dụng lại cập nhật trạng thái lung tung, không đúng

ý của mình.

Trong đối tượng Action này, bạn hoàn toàn có thể gửi thêm thông tin

thông qua thuộc tính payload. Ví dụ: thông tin là các giá trị mới của

state cần cập nhật chẳng hạn.

Dưới đây là đoạn mã minh họa cho một Action:

// Định nghĩa một action kèm thông tin username và password


const setUser = (user) => {
return {
type: "LOGIN",
payload: {
username : user.name,
password : user.password
}
}
}

“Reducers” là pure function để cập nhật, thay đổi giá trị state được

lưu trong store. Các Reducers sẽ căn cứ vào action và payload được

truyền vào mà trả về state với giá trị mới.

Ví dụ một đoạn mã dưới đây cách Reducers cập nhật state lưu thông

tin đăng nhập (username và password).

VNTALKING.COM 137
// Reducer
const initialState = {
username: '',
password: ''
};
const loggeduser = (state = initialState, action) => {
switch (action.type) {
case "LOGIN":
return {
username : action.payload.username,
password : action.payload.password
};
default:
return state;
}
};

Ok, Lý thuyết về Redux cơ bản chỉ như vậy thôi, chúng ta cũng không

cần phài đào sâu quá làm gì, mình biết những cái cần thiết trước và

ứng dụng được trong dự án là được.

Phần tiếp theo, chúng ta cùng nhau thực hành một ví dụ nhỏ về cách

cài đặt, cấu hình để sử dụng Redux trong dự án React Native nhé.

Cài đặt và cấu hình Redux cho dự án

Để cài đặt Redux cho dự án React Native, chúng ta cũng thực hiện

giống như cài đặt một dependencies bình thường khác.

npm install redux

npm install react-redux

VNTALKING.COM 138
Sau khi cài đặt xong thì chúng ta tiến hành cấu hình cơ bản để Redux

hoạt động được với dự án. Bạn tải mã nguồn starter cho phần này về

rồi cùng mình thực hành nhé.

Tải mã nguồn trước khi thực hành

Hãy sử dụng mã nguồn này trước khi vào thực hành

Chuong9-Redux-Starter.zip

Trong ví dụ này, chúng ta sẽ tạo một ứng dụng tăng giảm biến đếm

và hiển thị ra ngoài màn hình. Ví dụ này đã được sử dụng trong

Chương 6 - phần State. Tuy nhiên, ở chương 6, chúng ta thực hiện lưu

state trực tiếp trong component. Đến chương này, chúng ta sẽ thử

dùng Redux để lưu và quản lý state trong store.

Hình ảnh ứng dụng sau khi hoàn thành:

VNTALKING.COM 139
Trước hết, chúng ta dựng lại giao diện ứng dụng giống như trên đã

nhé (bỏ qua xử lý logic).

screens/Home.js

import React, { useState } from 'react';


import { StyleSheet, View, Text, TouchableOpacity} from 'react-
native';

const Home = () => {


const handleIncreament = () => {
console.log("Tăng điểm")
};

const handleDecreament = () => {


console.log("Giảm điểm")
};
return (
<View style={{flex: 1}}>
<View style={{alignItems: 'center',
backgroundColor:"#cc3333"}}>
<Text style={styles.textHeader}>Giới thiệu sử dụng
Redux</Text>
<Text style={{color: "#FFFFFF"}}>VNTALKING.COM</Text>
</View>
<View style={styles.container}>
<Text style={styles.title_text}>Bộ đếm 2.0</Text>
<Text style={styles.counter_text}>0</Text>

<TouchableOpacity onPress={handleIncreament}
style={styles.btn}>
<Text style={styles.btn_text}> Tăng điểm </Text>
</TouchableOpacity>

<TouchableOpacity
onPress={handleDecreament}
style={{ ...styles.btn, backgroundColor: '#6e3b3b'
}}>
<Text style={styles.btn_text}> Giảm điểm </Text>
</TouchableOpacity>
</View>
</View>
)

VNTALKING.COM 140
}
const styles = StyleSheet.create({
textHeader: {
fontSize: 18,
fontWeight: "bold",
color: "#FFFFFF"
},
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
flexDirection: 'column',
padding: 50,
},
title_text: {
fontSize: 40,
fontWeight: '900',
marginBottom: 55,
},
counter_text: {
fontSize: 35,
fontWeight: '900',
margin: 15,
color: '#D64545'
},
btn: {
backgroundColor: '#086972',
padding: 10,
margin: 10,
borderRadius: 10,
},
btn_text: {
fontSize: 23,
color: '#fff',
},
})

export default Home;

Còn file App.js sẽ cấu hình để trỏ sang màn hình Home.

VNTALKING.COM 141
App.js

import Home from './screens/Home';


import React from 'react';

export default function App() {


return <Home />;
}

Bước tiếp theo, chúng ta sẽ định nghĩa các action tương ứng với hai

hành động khi nhấn nút “tăng điểm” và “giảm điểm”.

Để cho mã nguồn dự án nó gọn gàng, mình sẽ tạo thư mục

“redux” dành riêng cho toàn bộ code liên quan tới redux.

Tạo file countAction.js trong thư mục redux và định nghĩa action

tương ứng như sau:

redux/countAction.js

export const increment = () => {


return {
type: 'INCRESE',
};
};

export const decrement = () => {


return {
type: 'DECRESE',
};
};

Sau đó, chúng ta tạo countReducer.js (vẫn để trong thư mục redux)

VNTALKING.COM 142
redux/countReducer.js

const initialState = {
count: 0,
};

export default (state = initialState, action) => {


switch (action.type) {
case 'INCRESE':
return {
...state,
count: state.count + 1,
};
case 'DECRESE':
return {
...state,
count: state.count - 1,
};
default:
return state;
}
};

Đây là reducer dùng để cập nhật state lưu giữ trạng thái biến đếm,

với giá trị mặc định là 0, tức là mỗi lần mở ứng dụng, ứng dụng sẽ

hiển thị giá trị bắt đầu là số 0.

Bước tiếp theo, chúng ta tạo một store để lưu giữ state, cụ thể là

“count” state.

Tạo một file store.js trong thư mục redux:

redux/store.js

import { createStore, combineReducers} from 'redux';


import CountReducer from './countReducer';

const rootReducer = combineReducers({

VNTALKING.COM 143
count: CountReducer,
});

export const store = createStore(rootReducer);

Gần xong rồi! Sau khi các món ăn đã chuẩn bị xong hết rồi, rượu

ngon cũng đã sẵn sàng, giờ là đi mời các bạn hiền tới nhậu thôi

Đùa thôi, (viết sách nhiều khi bị tẩu hỏa nhập ma, mong bạn thông

cảm!). Bước tiếp theo là chúng ta thực hiện kết nối store vừa tạo ở

trên tới ứng dụng.

Chúng ta quay trở lại file App.js và thay đổi code một chút:

App.js

import Home from './screens/Home';


import React from 'react';
import { Provider } from 'react-redux';
import { store } from './redux/store';

export default function App() {


return (
<Provider store={store}>
<Home />
</Provider>
);
}

Trong đoạn code trên, mình bọc toàn bộ màn hình ứng dụng vào

trong Provider.

VNTALKING.COM 144
Như vậy là đã kết nối xong rồi đấy. Giờ là lúc sử dụng thôi. Quay lại

màn hình Home, mình sẽ chỉnh sửa code một chút để nó lưu giá trị

vào store, sau đó lấy ra để hiển thị lên màn hình.

screens/Home.js

import React from 'react';


import { StyleSheet, View, Text, TouchableOpacity} from 'react-
native';

import { useSelector, useDispatch } from 'react-redux';


import { increment, decrement } from '../redux/countAction';

const Home = () => {


const dispatch = useDispatch();
const count = useSelector((store) => store.count.count);

const handleIncreament = () => {


console.log("Tăng điểm");
dispatch(increment());
};

const handleDecreament = () => {


console.log("Giảm điểm");
dispatch(decrement());
};
return (
<View style={{flex: 1}}>
<View style={{alignItems: 'center',
backgroundColor:"#cc3333"}}>
<Text style={styles.textHeader}>Giới thiệu sử dụng
Redux</Text>
<Text style={{color: "#FFFFFF"}}>VNTALKING.COM</Text>
</View>
<View style={styles.container}>
<Text style={styles.title_text}>Bộ đếm 2.0</Text>
<Text style={styles.counter_text}>{count}</Text>

<TouchableOpacity onPress={handleIncreament}
style={styles.btn}>
<Text style={styles.btn_text}> Tăng điểm </Text>
</TouchableOpacity>

VNTALKING.COM 145
<TouchableOpacity
onPress={handleDecreament}
style={{ ...styles.btn, backgroundColor: '#6e3b3b'
}}>
<Text style={styles.btn_text}> Giảm điểm </Text>
</TouchableOpacity>
</View>
</View>
)
}

Ở đây, chúng ta sử dụng các hooks được cung cấp bởi thư viện react-

redux để gửi action và truy cập vào store. Cụ thể là hai hooks sau:

• useSelector: Giúp truy xuất vào store để lấy state.

• useDispatch: Giúp gửi action để kích hoạt thay đổi state

Các bạn chạy ứng dụng để tận hưởng thành quả nhé:

VNTALKING.COM 146
Tải mã nguồn tham khảo

Hãy thực hành chạy thử với mã nguồn đầy đủ của phần này nhé

Chuong9-Redux-Counter-Final.zip

Tổng kết

Qua tìm hiểu lý thuyết và thực hành ví dụ trên, bạn thấy Redux này

thế nào? Việc quản lý State qua redux nó có ích lợi gì không?

Có thể bạn sẽ bật ra ngay ý nghĩ kiểu: Việc để state trong store tập

trung như này chả khác gì khi vừa nhận lương tháng, vội vàng cất vào

két sắt, xong lại vội vàng mở két lấy ra để đi uống bia cả. Thực tế thì

bạn nói cũng có ý đúng!

Quan điểm cá nhân: với những trường hợp state nào mà không cần

chia sẻ cho nhiều màn hình thì đúng là không cần phải quản lý tập

trung, gây phức tạp thêm tình hình. Tuy nhiên, nếu bạn là người ngăn

nắp, thích gọn gàng thì việc quản lý tập trung state về một mối cũng

có nhiều điểm lợi thế. Đặc biệt là khoản debug ứng dụng qua React

Dev Tools.

VNTALKING.COM 147

You might also like