Trong quá trình phát triển ứng dụng React, việc sử dụng hook useState là một phần không thể thiếu. Tuy nhiên, không phải ai cũng có thể sử dụng useState thành thạo ngay từ đầu mà không vấp phải những sai lầm. Trong bài viết này, hãy cùng VietnamWorks inTECH khám phá bốn sai lầm quan trọng mà các lập trình viên thường gặp khi sử dụng useState trong ứng dụng React của họ.

1. Sai lầm 1: Quên xem xét trạng thái trước đó 

Khi làm việc với hook useState của React, một sai lầm phổ biến mà hầu hết mọi người hay gặp phải là không tính đến trạng thái mới nhất khi cập nhật nó. Sơ suất này có thể dẫn đến các hành vi không mong muốn, đặc biệt là khi bạn đang xử lý các cập nhật nhiều trạng thái hay yêu cầu sự nhanh chóng.

1.1. Hiểu Vấn Đề

Hãy tưởng tượng bạn đang xây dựng một bộ đếm trong React. Mục tiêu của bạn là tăng số lần mỗi khi người dùng nhấp vào nút (button). Nhiều bạn sẽ nghĩ ngay đây cách thực hiện là thêm 1 vào giá trị trạng thái hiện tại. Tuy nhiên, điều này có thể gây ra một vài rắc rối.

import React, { useState } from 'react';

const CounterComponent = () => {
const [counter, setCounter] = useState(0);

const incrementCounter = () => {
setCounter(counter + 1); // Might not always work as expected
};

return (
<div>
<p>Counter: {counter}</p>
<button onClick={incrementCounter}>Increment</button>
</div>
);
};

export default CounterComponent;

Trong ví dụ trên, incrementCounter cập nhật bộ đếm dựa trên giá trị hiện tại của nó. Điều này nhìn có vẻ đơn giản, nhưng khi React kết hợp nhiều setCounter cuộc gọi lại với nhau hoặc các cập nhật các trạng thái khác sẽ gây trở ngại, dẫn đến việc counter cập nhật thường không chính xác.

1.2. Cách khắc phục

Để tránh vấn đề này, hãy sử dụng phiên bản hàm của phương thức setCounter. Phiên bản này nhận một hàm làm đối số của nó, mà React sẽ gọi với giá trị trạng thái mới nhất. Điều này đảm bảo rằng bạn luôn làm việc với giá trị mới nhất của trạng thái.

import React, { useState } from 'react';

const CounterComponent = () => {
const [counter, setCounter] = useState(0);

const incrementCounter = () => {
setCounter(counter + 1); // Might not always work as expected
};

return (
<div>
<p>Counter: {counter}</p>
<button onClick={incrementCounter}>Increment</button>
</div>
);
};

export default CounterComponent;

Trong đoạn code đã được sửa này, incrementCounter sử dụng một hàm để cập nhật trạng thái. Hàm này nhận được trạng thái mới nhất (prevCounter) và trả về trạng thái đã được cập nhật. Cách tiếp cận này đáng tin cậy hơn nhiều, đặc biệt là khi các cập nhật xảy ra nhanh chóng hoặc nhiều lần liên tiếp.

2. Sai lầm 2: Bỏ qua tính bất biến của trạng thái

2.1. Hiểu vấn đề

Trong React, trạng thái phải được coi là bất biến. Một sai lầm phổ biến là thay đổi trạng thái trực tiếp, đặc biệt là với các cấu trúc dữ liệu phức tạp như các đối tượng và mảng. Cùng xem xét ví dụ dưới đây:

import React, { useState } from 'react';

const ProfileComponent = () => {
const [profile, setProfile] = useState({ name: 'John', age: 30 });

const updateAge = () => {
profile.age = 31; // Directly mutating the state
setProfile(profile);
};

return (
<div>
<p>Name: {profile.name}</p>
<p>Age: {profile.age}</p>
<button onClick={updateAge}>Update Age</button>
</div>
);
};

export default ProfileComponent;

Đoạn mã này sử dụng cách thay đổi đối tượng profile một cách trực tiếp, điều này là không đúng. Những thay đổi như vậy sẽ không kích hoạt việc render lại và dẫn đến hành vi không thể đoán trước.

2.2. Cách khắc phục

Luôn tạo một đối tượng hoặc mảng mới khi cập nhật trạng thái để duy trì tính bất biến. Sử dụng toán tử spread khi bạn làm việc với những hoạt động này.

import React, { useState } from 'react';

const ProfileComponent = () => {
const [profile, setProfile] = useState({ name: 'John', age: 30 });

const updateAge = () => {
setProfile({...profile, age: 31}); // Correctly updating the state
};

return (
<div>
<p>Name: {profile.name}</p>
<p>Age: {profile.age}</p>
<button onClick={updateAge}>Update Age</button>
</div>
);
};

export default ProfileComponent;

Trong đoạn code trên, updateAge sử dụng toán tử spread để tạo ra một đối tượng profile mới với “age” được cập nhật mà vẫn duy trì tính bất biến của trạng thái.

3. Sai lầm 3: Hiểu sai về cập nhật không đồng bộ

3.1. Hiểu rõ vấn đề

Cập nhật trạng thái trong React thông qua useState là phương thức không đồng bộ. Điều này thường gây nhầm lẫn, đặc biệt là khi có nhiều cập nhật trạng thái được thực hiện liên tục và nhanh chóng. Các lập trình viên có thể mong đợi trạng thái thay đổi ngay sau một cuộc gọi setState, nhưng trong thực tế, React gom nhóm các cập nhật này lại với nhau vì lý do hiệu suất.

Hãy cùng xem ví dụ dưới đây:

import React, { useState } from 'react';

const AsyncCounterComponent = () => {
const [count, setCount] = useState(0);

const incrementCount = () => {
setCount(count + 1);
setCount(count + 1);
// Developer expects count to be incremented twice
};

return (
<div>
<p>Count: {count}</p>
<button onClick={incrementCount}>Increment Count</button>
</div>
);
};

export default AsyncCounterComponent;

Trong ví dụ này, người dùng dự định tăng gấp đôi count. Tuy nhiên, do tính chất không đồng bộ của việc cập nhật trạng thái, cả hai lệnh setCount gọi đều dựa trên cùng một trạng thái ban đầu, dẫn đến việc chỉ count tăng một lần.

3.2. Cách khắc phục

Để xử lý chính xác các cập nhật không đồng bộ, hãy sử dụng biểu mẫu cập nhật chức năng của setCount. Điều này đảm bảo rằng mỗi bản cập nhật đều dựa trên trạng thái gần đây nhất.

import React, { useState } from 'react';

const AsyncCounterComponent = () => {
const [count, setCount] = useState(0);

const incrementCount = () => {
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1);
// Now each update correctly depends on the most recent state
};
// Optional: Use useEffect to see the updated state
useEffect(() => {
console.log(count); // 2
}, [count]);

return (
<div>
<p>Count: {count}</p>
<button onClick={incrementCount}>Increment Count</button>
</div>
);
};

export default AsyncCounterComponent;

Trong đoạn code trên, mỗi lần gọi setCount đều sử dụng giá trị mới nhất của trạng thái, đảm bảo các cập nhật chính xác và tuần tự. Cách tiếp cận này là rất quan trọng đối với các hoạt động phụ thuộc vào trạng thái hiện tại, đặc biệt là khi có nhiều cập nhật trạng thái diễn ra liên tục.

4. Sai lầm 4: Sử dụng Trạng thái sai cho Dữ liệu Phụ thuộc

4.1. Hiểu rõ vấn đề

Một lỗi thường gặp là sử dụng trạng thái cho dữ liệu có thể được suy ra từ trạng thái hiện tại hoặc các props hiện có. Trạng thái dư thừa này có thể dẫn đến code trở nên phức tạp và dễ gây lỗi.

Ví dụ:

import React, { useState } from 'react';

const GreetingComponent = ({ name }) => {
const [greeting, setGreeting] = useState(`Hello, ${name}`);

return (
<div>{greeting}</div>
);
};

export default GreetingComponent;

Ở đây, trạng thái của greeting là không cần thiết vì nó có thể được suy ra trực tiếp từ “name”.

4.2. Cách khắc phục

Thay vì sử dụng trạng thái, hãy lấy dữ liệu trực tiếp từ trạng thái hoặc props hiện có.

import React from 'react';

const GreetingComponent = ({ name }) => {
const greeting = `Hello, ${name}`; // Directly derived from props

return (
<div>{greeting}</div>
);
};

export default GreetingComponent;

Trong đoạn code trên, greeting được tính toán trực tiếp từ prop name, làm đơn giản hóa thành phần và tránh việc quản lý trạng thái không cần thiết.

Lời kết

Sử dụng hook useState một cách hiệu quả trong React là rất quan trọng để xây dựng các ứng dụng đáng tin cậy và hiệu quả. Bằng cách hiểu và tránh những sai lầm phổ biến mà VietnamWorks inTECH vừa nêu trên, bạn có thể đảm bảo hành vi của thành phần mượt mà và dự đoán được hơn. Lưu ngay những thông tin này để nâng cao hành trình phát triển React của bạn và tạo ra các ứng dụng mạnh mẽ.

VietnamWorks inTECH