Props & Refs
Quy ước đặt tên props, giá trị mặc định, accessibility (alt, ARIA), key ổn định, ref callback và tránh isMounted (theo React/JSX Style Guide).
Props
Tên prop: camelCase; prop là component thì PascalCase
- Tên prop dùng camelCase.
- Nếu giá trị prop là React component thì tên prop có thể dùng PascalCase (ví dụ
Component={SomeComponent}).
// ❌ Tránh
<Foo
UserName="hello"
phone_number={12345678}
/>
// ✅ Tốt
<Foo
userName="hello"
phoneNumber={12345678}
Component={SomeComponent}
/>
Prop boolean true: bỏ giá trị
Khi prop có giá trị đúng là true, chỉ ghi tên prop, không ghi ={true}.
// ❌ Tránh
<Foo hidden={true} />
// ✅ Tốt
<Foo hidden />
// ✅ Tốt (một dòng)
<Foo hidden />
Thẻ img: luôn có alt
Mọi thẻ <img> phải có prop alt. Ảnh trang trí: alt="" hoặc dùng role="presentation".
// ❌ Tránh
<img src="hello.jpg" />
// ✅ Tốt
<img src="hello.jpg" alt="Mô tả ảnh" />
// ✅ Tốt: ảnh trang trí
<img src="hello.jpg" alt="" />
<img src="hello.jpg" role="presentation" />
Không dùng "image", "photo", "picture" trong alt
Screen reader đã đọc thẻ img là ảnh; không cần lặp lại từ "image", "photo", "picture" trong alt.
// ❌ Tránh
<img src="hello.jpg" alt="Picture of me waving hello" />
// ✅ Tốt
<img src="hello.jpg" alt="Me waving hello" />
ARIA role: chỉ dùng role hợp lệ
Chỉ dùng ARIA role hợp lệ, không dùng role trừu tượng (abstract). Ví dụ: role="datepicker" không phải role chuẩn; role="range" là abstract.
// ❌ Tránh
<div role="datepicker" />
<div role="range" />
// ✅ Tốt
<div role="button" />
Không dùng accessKey
Không dùng accessKey trên element — dễ xung đột phím tắt với screen reader và bàn phím.
// ❌ Tránh
<div accessKey="h" />
// ✅ Tốt
<div />
Key: dùng ID ổn định, tránh index
Không dùng index của mảng làm key khi thứ tự có thể thay đổi (thêm/xóa/sắp xếp). Dùng id ổn định (từ data).
// ❌ Tránh
{
todos.map((todo, index) => <Todo {...todo} key={index} />);
}
// ✅ Tốt
{
todos.map((todo) => <Todo {...todo} key={todo.id} />);
}
defaultProps cho prop không bắt buộc
Với TypeScript: prop optional nên có giá trị mặc định (trong destructuring hoặc defaultProps) để code dễ đọc và giảm kiểm tra undefined.
// ✅ Tốt: default trong destructuring
type Props = { foo: number; bar?: string; children?: React.ReactNode };
function SFC({ foo, bar = "", children = null }: Props) {
return (
<div>
{foo}
{bar}
{children}
</div>
);
}
// ✅ Tốt: defaultProps (nếu team dùng)
SFC.defaultProps = { bar: "", children: null };
Spread props: dùng có chừng mực
Dùng spread props ({...props}) có chừng mực. Ưu tiên lọc bớt prop không cần trước khi truyền xuống để tránh truyền prop thừa hoặc không hợp lệ.
// ❌ Tránh: truyền toàn bộ props
function Wrapper(props: Props) {
return <WrappedComponent {...props} />;
}
// ✅ Tốt: chỉ truyền props cần thiết
function Wrapper({ irrelevantProp, ...relevantProps }: Props) {
return <WrappedComponent {...relevantProps} />;
}
Refs
Dùng ref callback, không dùng string ref
Luôn dùng ref dạng callback (hoặc useRef + gán). Không dùng string ref (đã deprecated).
// ❌ Tránh (string ref - deprecated)
<Foo ref="myRef" />;
// ✅ Tốt (function component + useRef)
const myRef = useRef<HTMLDivElement>(null);
return <Foo ref={myRef} />;
// ✅ Tốt (callback ref khi cần)
<Foo
ref={(el) => {
this.myRef = el;
}}
/>;
isMounted
Không dùng isMounted
Không dùng isMounted. Đây là anti-pattern, không có trong component dạng class ES6 và đang bị deprecated. Thay vào đó xử lý cleanup trong useEffect (abort controller, flag cancelled) hoặc kiểm tra điều kiện trước khi setState.
// ❌ Tránh
if (this.isMounted()) {
this.setState({ ... });
}
// ✅ Tốt: với function component — cleanup trong useEffect
useEffect(() => {
let cancelled = false;
fetchData().then((data) => {
if (!cancelled) setData(data);
});
return () => { cancelled = true; };
}, []);