Redux cho người mới bắt đầu – Tìm hiểu kiến thức cơ bản về Redux với các ví dụ về mã
05/12/2023 01:24
Redux có thể gây nhầm lẫn cho các nhà phát triển React mới bắt đầu hiểu. Có rất nhiều khái niệm bạn cần biết để sử dụng nó đúng cách, như bộ giảm tốc, hành động, cửa hàng, hàm thuần túy, tính bất biến, v.v.
Nhưng mọi nhà phát triển React nên biết những điều cơ bản về cách làm việc với Redux, vì các dự án công nghiệp thường sử dụng Redux để quản lý các dự án lớn hơn.
Vì vậy, trong bài viết này, chúng ta sẽ khám phá những kiến thức cơ bản về Redux và cách sử dụng nó.
Đây là bản xem trước của ứng dụng mà chúng tôi sẽ xây dựng trong bài viết này. Đó là một dự án tuyệt vời mà bạn có thể thêm vào danh mục đầu tư và sơ yếu lý lịch của mình.
Redux là gì?
Redux là thư viện quản lý trạng thái giúp bạn quản lý trạng thái tốt hơn trong ứng dụng của mình.
Thư viện Redux không dành riêng cho React. Đó là một thư viện mà bạn có thể sử dụng trong bất kỳ thư viện hoặc khung công tác nào khác như Angular, Vue và thậm chí cả JavaScript thuần.
Nhưng các nhà phát triển chủ yếu sử dụng Redux khi làm việc với React.
Redux cung cấp một cửa hàng duy nhất mà bạn có thể sử dụng để quản lý một lượng lớn dữ liệu.
Cách bắt đầu với Redux
Hãy tạo một dự án React mới để chúng ta có thể tìm hiểu những điều cơ bản về Redux.
Thực hiện lệnh sau trong dấu nhắc lệnh/thiết bị đầu cuối để tạo dự án React mới bằng ứng dụng tạo phản ứng:
npx create-react-app redux-demo
npx
trong trường hợp này cho phép chúng ta sử dụng góicreate-react-app
npm để tạo dự án React mới mà không cần cài đặt nó trên máy cục bộ của chúng ta.
Khi bạn đã tạo dự án, hãy xóa tất cả các tệp khỏi thư mục src
và tạo một tệp mới index.js
bên trong src
thư mục.
Bây giờ hãy mở lại terminal và thực hiện lệnh sau từ thư mục redux-demo
:
npm install redux@4.1.0
Lệnh trên sẽ cài đặt thư viện Redux với phiên bản 4.1.0
để sử dụng trong dự án của bạn (là phiên bản mới nhất tại thời điểm viết bài này).
Cách tạo cửa hàng Redux
Trong Redux, bạn sử dụng cửa hàng để quản lý và theo dõi dữ liệu đang thay đổi trong ứng dụng.
Để tạo cửa hàng, chúng ta cần nhập hàm createStore
như thế này:
import { createStore } from 'redux';
Hàm createStore
chấp nhận ba đối số:
- đối số đầu tiên là một hàm thường được gọi là bộ giảm tốc (bắt buộc)
- đối số thứ hai là giá trị ban đầu của trạng thái (tùy chọn)
- đối số thứ ba là trình tăng cường nơi chúng tôi có thể chuyển phần mềm trung gian, nếu có (tùy chọn)
Hãy nhìn vào đoạn mã dưới đây:
import { createStore } from 'redux';
const reducer = (state, action) => {
console.log('reducer called');
return state;
};
const store = createStore(reducer, 0);
Ở đây, trước tiên chúng ta đã xác định hàm rút gọn bằng cú pháp hàm mũi tên ES6. Bạn có thể sử dụng chức năng bình thường thay vì chức năng mũi tên nếu muốn.
Bên trong hàm giảm tốc, chúng tôi đang ghi một số văn bản vào bảng điều khiển và sau đó trả về giá trị trạng thái từ hàm.
Sau đó, chúng ta chuyển hàm rút gọn đó cho hàm createStore
làm đối số đầu tiên và 0
làm giá trị ban đầu của trạng thái làm đối số thứ hai.< /span>
Hàm createStore
trả về một cửa hàng mà chúng ta có thể sử dụng để quản lý dữ liệu ứng dụng.
Hàm giảm tốc nhận trạng thái và hành động làm tham số.
Giá trị ban đầu của trạng thái mà chúng ta chuyển dưới dạng 0
cho hàm createStore
được tự động chuyển dưới dạng giá trị của state
tham số.
Nhưng cách phổ biến hơn nhiều là khởi tạo trạng thái bên trong bộ giảm tốc thay vì chuyển nó làm đối số thứ hai cho hàm createStore
như thế này:
import { createStore } from 'redux';
const reducer = (state = 0, action) => {
console.log('reducer called');
return state;
};
const store = createStore(reducer);
Ở đây, chúng tôi đang sử dụng cú pháp tham số mặc định ES6 để khởi tạo tham số trạng thái thành giá trị 0
.
Sau khi cửa hàng được tạo, chúng ta có thể sử dụng phương thức subscribe
do cửa hàng cung cấp để đăng ký các thay đổi trong cửa hàng như dưới đây:
store.subscribe(() => {
console.log('current state', store.getState());
});
Ở đây, bằng cách sử dụng hàm subscribe
, chúng tôi đang đăng ký một hàm gọi lại sẽ được gọi sau khi cửa hàng được thay đổi.
Và bên trong hàm gọi lại, chúng tôi đang gọi phương thức store.getState
để lấy giá trị hiện tại của trạng thái.
Bây giờ, hãy mở tệp src/index.js
và thêm các nội dung sau vào đó:
import { createStore } from 'redux';
const reducer = (state = 0, action) => {
console.log('reducer called');
return state;
};
const store = createStore(reducer);
store.subscribe(() => {
console.log('current state', store.getState());
});
Bây giờ, nếu bạn chạy ứng dụng bằng cách thực thi lệnh npm start
từ thiết bị đầu cuối và truy cập http://localhost:3000/reducer called
được in trong bảng điều khiển., bạn sẽ thấy thông báo
Cách thay đổi cửa hàng
Bây giờ chúng ta đã hoàn tất việc tạo cửa hàng. Nhưng hiện tại cửa hàng không còn hữu dụng với chúng tôi nữa. Điều này là do cửa hàng được kết nối bằng chức năng bộ giảm tốc nhưng chúng tôi chưa thêm bất kỳ mã nào bên trong bộ giảm tốc để quản lý cửa hàng. Vì vậy, hãy làm điều đó.
Cách duy nhất để thay đổi cửa hàng là gửi hành động.
Một hành động là một đối tượng được gửi đến cửa hàng như thế này:
store.dispatch({
type: 'INCREMENT'
})
Ở đây, chúng tôi đang gọi hàm điều phối có sẵn trên store
để gửi một hành động có loại INCREMENT
tới cửa hàng.
Hàm điều phối lấy một đối tượng làm tham số được gọi là một hành động.
Hành động phải có thuộc tính type
như được hiển thị ở trên. Nếu bạn không chuyển thuộc tính type
thì bạn sẽ gặp lỗi.
Đó là một thông lệ và nên chỉ định giá trị type
bằng chữ hoa.
Loại có thể là bất kỳ thao tác nào bạn muốn thực hiện, như ADD_USER
, DELETE_RECORD
, GET_USERS
, v.v.
Nếu bạn có nhiều từ, bạn có thể phân tách chúng bằng dấu gạch dưới như thế này { type: 'INCREMENT_NUMBER' }
.
Bây giờ, hãy mở tệp index.js
và thay thế nội dung của nó bằng mã sau:
import { createStore } from 'redux';
const reducer = (state = 0, action) => {
if (action.type === 'INCREMENT') {
return state + 1;
} else if (action.type === 'DECREMENT') {
return state - 1;
}
return state;
};
const store = createStore(reducer);
store.subscribe(() => {
console.log('current state', store.getState());
});
store.dispatch({
type: 'INCREMENT'
});
store.dispatch({
type: 'INCREMENT'
});
store.dispatch({
type: 'DECREMENT'
});
Bây giờ, nếu bạn chạy ứng dụng bằng cách thực thi lệnh npm start
từ thiết bị đầu cuối, bạn sẽ thấy các nhật ký sau được in trong bảng điều khiển:
Như bạn có thể thấy, đối với mỗi hành động được gửi đến cửa hàng, cửa hàng sẽ được thay đổi. Vì vậy, chúng tôi có thể thấy các giá trị khác nhau của trạng thái trong bảng điều khiển.
Trong đoạn mã trên, hàm giảm tốc của chúng ta trông như thế này:
const reducer = (state = 0, action) => {
if (action.type === 'INCREMENT') {
return state + 1;
} else if (action.type === 'DECREMENT') {
return state - 1;
}
return state;
};
Bất cứ khi nào chúng ta gọi hàm store.dispatch
, hàm rút gọn sẽ được gọi. Bất cứ thứ gì được trả về từ bộ giảm tốc sẽ trở thành giá trị mới của cửa hàng.
Vì vậy, lần đầu tiên chúng tôi gửi một hành động đến cửa hàng như thế này:
store.dispatch({
type: 'INCREMENT'
});
điều kiện if đầu tiên bên trong hàm giảm tốc sẽ được thực thi. Nó sẽ tăng giá trị state
lên 1
ban đầu được khởi tạo thành 0
bằng cú pháp tham số mặc định của ES6. Sau đó nó sẽ được trả về từ hàm giảm tốc.
Lưu ý rằng chúng tôi đang sử dụng giá trị của state
để tính giá trị mới và chúng tôi không sửa đổi state
ban đầu giá trị như thế này:
if (action.type === 'INCREMENT') {
state = state + 1;
return state;
}
Vì vậy, đoạn mã trên không đúng, vì trong bộ giảm tốc chúng ta không nên sửa đổi trạng thái ban đầu. Làm như vậy sẽ tạo ra sự cố trong ứng dụng của bạn và do đó không nên làm như vậy.
Và vì chúng tôi đã thêm chức năng store.subscribe
vào tệp index.js
nên chúng tôi nhận được thông báo về việc thay đổi cửa hàng khi chúng tôi có thể xem nhật ký trong bảng điều khiển.
Vì vậy, khi chúng ta gọi lại công văn với loại INCREMENT
, điều kiện if đầu tiên sẽ được thực thi lại. Vì vậy, nó sẽ thêm 1 vào giá trị trạng thái trước đó là 1 và giá trị trạng thái cuối cùng sẽ trở thành 2.
Sau đó, chúng tôi sẽ gửi hành động DECREMENT
đến cửa hàng như thế này:
store.dispatch({
type: 'DECREMENT'
});
sẽ thực thi điều kiện else bên trong bộ giảm tốc và sẽ giảm giá trị trạng thái đi 1 (vì vậy 2 - 1 sẽ trở thành 1).
Lưu ý rằng, bên trong bộ giảm tốc, chúng ta cũng sẽ trả về trạng thái ở cuối. Vì vậy, nếu không có điều kiện nào phù hợp thì trạng thái mặc định trước đó sẽ được hàm trả về.
Thực tế phổ biến là sử dụng câu lệnh switch bên trong bộ giảm tốc thay vì điều kiện if-else như thế này:
const reducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
};
Ngoài loại, chúng ta cũng có thể chuyển thông tin bổ sung như một phần của hành động.
Thay thế nội dung của tệp index.js
bằng mã sau:
import { createStore } from 'redux';
const reducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + action.payload;
case 'DECREMENT':
return state - action.payload;
default:
return state;
}
};
const store = createStore(reducer);
store.subscribe(() => {
console.log('current state', store.getState());
});
store.dispatch({
type: 'INCREMENT',
payload: 1
});
store.dispatch({
type: 'INCREMENT',
payload: 5
});
store.dispatch({
type: 'DECREMENT',
payload: 2
});
Bây giờ, nếu bạn chạy ứng dụng bằng cách thực thi lệnh npm start
từ thiết bị đầu cuối, bạn sẽ thấy các nhật ký sau được in trong bảng điều khiển:
Ở đây, trong khi gửi một hành động đến cửa hàng, chúng tôi chuyển payload
với một số giá trị mà chúng tôi đang sử dụng bên trong bộ giảm tốc để tăng hoặc giảm cửa hàng giá trị.
Ở đây, chúng tôi đã sử dụng payload
làm tên thuộc tính nhưng bạn có thể đặt tên tùy ý.
Chức năng giảm tốc của chúng tôi bây giờ trông như thế này:
const reducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + action.payload;
case 'DECREMENT':
return state - action.payload;
default:
return state;
}
};
Vì vậy, khi chúng tôi gửi các hành động có loại INCREMENT
như thế này:
store.dispatch({
type: 'INCREMENT',
payload: 1
});
store.dispatch({
type: 'INCREMENT',
payload: 5
});
đoạn mã sau từ bộ giảm tốc sẽ được thực thi:
return state + action.payload;
Điều này trước tiên sẽ thêm 1 và sau đó là 5 vào giá trị trước đó của trạng thái, vì vậy chúng ta đi từ 1 đến 6. Và do loại hành động DECREMENT
:
store.dispatch({
type: 'DECREMENT',
payload: 2
});
chúng ta đi từ 6 đến 4. Vậy giá trị cuối cùng của cửa hàng sẽ trở thành 4.