Menu

Render có điều kiện trong React: if, ternary, && và null

Render có điều kiện trong React chỉ là JavaScript thuần: một câu lệnh if, toán tử ba ngôi hoặc && quyết định component trả về JSX nào. Tìm hiểu từng mẫu, số 0 lạc mà && có thể in ra, việc trả về null, và vì sao ẩn một component không giống với không render nó.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Render có điều kiện (conditional rendering) trong React nghĩa là chọn thứ component trả về bằng JavaScript thông thường: một câu lệnh if trước return, toán tử ba ngôi (ternary) cond ? a : b bên trong JSX, hoặc cond && <Thing /> để hiển thị một thứ hoặc không gì cả. Không có cú pháp template đặc biệt nào phải học.

Bấm nút, cả lời chào lẫn nhãn nút đều đổi, vì mỗi toán tử ba ngôi chọn một chuỗi khác ở lần render tiếp theo. Đổi useState(false) thành useState(true), phần xem trước sẽ bắt đầu ở trạng thái đã đăng nhập.

Câu lệnh if và return sớm

Ngoặc nhọn của JSX nhận biểu thức, không nhận câu lệnh, nên bạn không thể viết {if (x) ...} bên trong markup. Nhưng bạn có thể viết bất kỳ câu lệnh if nào trước return. Khi cả một trạng thái của component trông khác hẳn (đang tải, lỗi, trống), hãy return sớm cho từng trường hợp và giữ markup chính cho trường hợp bình thường.

Mỗi nút đưa hộp thư vào một trạng thái khác nhau, và mỗi trạng thái có nhánh riêng, ngắn gọn, dễ đọc. Return sớm giữ luồng chính ở cuối mà không phải lồng nhau.

Toán tử ba ngôi bên trong JSX

Khi chỉ một phần nhỏ của markup thay đổi, một toán tử ba ngôi viết inline giữ mọi thứ gọn một chỗ: {isOpen ? <CloseIcon /> : <MenuIcon />}. Toán tử ba ngôi hợp với hai lựa chọn. Lồng nhiều toán tử ba ngôi cho ba lựa chọn trở lên sẽ nhanh chóng khó đọc:

// Hard to follow
{status === 'loading' ? <Spinner /> : status === 'error' ? <ErrorBox /> : <List />}

Khi gặp trường hợp đó, hãy chuyển logic thành một chuỗi if trước return (như ở trên) hoặc thành một object map (ở phần dưới).

&& và số 0 lạc

cond && <Thing /> render <Thing /> khi cond là truthy và không render gì khi nó là false. Cách này chạy được vì && trả về vế trái khi vế đó là falsy, và React không render gì với false, null và undefined.

Cái bẫy là 0 cũng là falsy, mà React lại render số. Vì vậy count && <Badge /> với count bằng 0 sẽ đặt nguyên một số 0 lên trang.

Khi không có tin nhắn chưa đọc, dòng đầu hiện "Broken: 0" trong khi dòng thứ hai không hiện gì sau "Fixed:". Bấm New message, cả hai dòng khớp nhau; bấm Mark all read, số 0 quay lại. Cách sửa là cho && một boolean thật sự: unread > 0, items.length > 0 hoặc Boolean(unread). Về nguyên tắc, chuỗi rỗng '' cũng có vấn đề tương tự, nhưng nó render ra thứ không nhìn thấy được, nên bạn hiếm khi để ý.

Trả về null

Một component có thể trả về null để không render gì. Một banner cảnh báo chỉ xuất hiện khi có điều cần cảnh báo là ví dụ phù hợp: component cha luôn render <Warning /> và component tự quyết định.

Hãy để ý console: hàm Warning ghi log ở mọi lần render, kể cả những lần nó trả về null. Trả về null bỏ qua phần đầu ra, không bỏ qua phần việc. Hook và effect của nó vẫn chạy, nên nếu một component tốn tài nguyên hoặc khởi động thứ gì đó (timer, subscription), hãy quyết định ở component cha và đừng render nó.

Lưu JSX vào biến

JSX là một giá trị, nên bạn có thể gán nó cho một biến, dựng dần bằng các câu lệnh if rồi thả vào markup sau. Cách này hữu ích khi một phần của bố cục lớn phụ thuộc vào nhiều điều kiện.

function Checkout({ cart, user }) {
    let action;
    if (!user) {
        action = <a href="/login">Log in to check out</a>;
    } else if (cart.length === 0) {
        action = <p>Your cart is empty.</p>;
    } else {
        action = <button>Pay now</button>;
    }

    return (
        <section>
            <h2>Your cart</h2>
            {action}
        </section>
    );
}

Chọn giữa nhiều component bằng một object

Khi lựa chọn là "một trong nhiều", một object ánh xạ mỗi giá trị tới một component sẽ ngắn hơn một chuỗi if dài hay một switch, và thêm một trường hợp chỉ tốn một dòng.

TABS[tab] chọn ra một component, và <Panel /> render nó. Biến này phải bắt đầu bằng chữ in hoa: JSX xem <panel /> là một thẻ HTML. Thêm một mục notifications vào TABS cùng component riêng của nó, một nút thứ tư sẽ xuất hiện.

Ẩn không giống với không render

Có hai cách làm một thứ biến mất, và chúng hoạt động khác nhau. show && <Counter /> gỡ component khỏi cây khi show là false. React unmount nó và vứt bỏ state, nên khi quay lại nó bắt đầu từ đầu. Ẩn nó bằng CSS (style={{ display: show ? 'block' : 'none' }}) giữ component ở trạng thái mount, nên state của nó được giữ lại.

Bấm cả hai bộ đếm vài lần, bỏ chọn ô, rồi chọn lại. Bộ đếm đầu tiên quay về 0, còn bộ đếm thứ hai vẫn giữ con số của nó. Không cách nào sai cả: gỡ bỏ phù hợp cho một form cần trống mỗi lần mở, ẩn phù hợp cho các tab cần giữ vị trí cuộn hoặc dữ liệu đã nhập. Trang về rendering giải thích cách React xác định một component vẫn là cùng một component giữa các lần render.

React 19.2 thêm lựa chọn thứ ba, <Activity mode="hidden">, ẩn các component con và giữ state của chúng như CSS, đồng thời dọn dẹp effect của chúng cho tới khi chúng được hiển thị lại.

Props và thuộc tính có điều kiện

Điều kiện không chỉ là chuyện phần tử nào xuất hiện. Prop nào cũng có thể nhận một giá trị được tính toán, nên một toán tử ba ngôi hoặc một phép so sánh bên trong thuộc tính thường là đủ:

<button disabled={!canSave} className={hasError ? 'field error' : 'field'}>
    Save
</button>
<input aria-invalid={hasError} placeholder={user ? user.email : 'you@example.com'} />

Khi giá trị của một prop là undefined, React bỏ hẳn thuộc tính đó, đây là cách gọn gàng để chỉ thêm thuộc tính trong một số trường hợp: title={isTruncated ? fullText : undefined}. Với các thuộc tính boolean như disabled và checked, hãy truyền true hoặc false và React sẽ thêm hoặc bỏ chúng.

Điều kiện trong danh sách

Để loại bỏ một số mục khỏi danh sách, hãy lọc mảng trước khi map thay vì trả về null từ bên trong map. items.filter((i) => i.done).map(...) đọc lên đúng như những gì nó làm, và trang danh sách và key minh họa điều này trong một ví dụ chạy được.

Câu hỏi thường gặp

Làm sao để viết câu lệnh if bên trong JSX?

Bạn không thể đặt câu lệnh if bên trong cặp ngoặc nhọn của JSX, vì ngoặc nhọn chỉ nhận biểu thức. Hãy dùng toán tử ba ngôi (cond ? a : b) hoặc && bên trong JSX, hoặc chạy if trước return và lưu JSX vào một biến.

Vì sao component của tôi hiển thị số 0?

count && <Badge /> trả về chính count khi nó bằng 0, và React render ra số 0. Hãy để vế trái là một boolean thật sự: count > 0 && <Badge />.

Làm sao để không render gì trong React?

Trả về null từ component, hoặc đặt null, undefined, false hay true trong JSX. React không render giá trị nào trong số đó.

Component trả về null có còn chạy không?

Có. Hàm của nó vẫn chạy, hook vẫn chạy và effect vẫn được kích hoạt. Trả về null chỉ có nghĩa là nó không thêm gì vào trang. Để bỏ qua hoàn toàn phần việc này, đừng render component đó từ component cha.

Nên ẩn component bằng CSS hay gỡ bỏ nó?

Gỡ bỏ (show && <Panel />) sẽ unmount component, nên state của nó bị vứt bỏ và lần sau bắt đầu lại từ đầu. Ẩn bằng display: none giữ component ở trạng thái mount và giữ nguyên state. Hãy chọn dựa trên việc state có cần được giữ lại hay không.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu