CodeGym /Các khóa học /ChatGPT Apps /Quản lý giao diện hiển thị:

Quản lý giao diện hiển thị: displayMode, maxHeight, borders, theme, layout

ChatGPT Apps
Mức độ , Bài học
Có sẵn

1. Vì sao cần quản lý giao diện hiển thị

Hiện tại, widget của bạn rất có thể trông như “một React component bình thường”: một div, danh sách phần tử, vài nút bấm. Trên web thông thường, vậy là đủ. Nhưng trong ChatGPT có một khác biệt: UI của bạn chạy bên trong khung chat, nơi người dùng đã có nhiều ngữ cảnh hình ảnh — tin nhắn, các App khác, giao diện thoại, cộng thêm giới hạn kích thước vùng chứa.

Hãy nhớ hai điều quan trọng.

Thứ nhất, widget có chế độ hiển thị (displayMode): inline, fullscreen, đôi khi có PiP. Chế độ quyết định diện tích khả dụng, hành vi cuộn và kỳ vọng của người dùng.

Thứ hai, nền tảng cung cấp cho widget giới hạn về chiều cao (maxHeight) và chủ đề (theme). Nếu bạn phớt lờ chúng và vẽ một thứ cỡ Notion ngay trong một tin nhắn, khung chat sẽ biến thành “hố đen”, nơi mọi thứ chìm vào một iframe khổng lồ. OpenAI khuyến nghị rõ ràng rằng UI nên gọn gàng và tôn trọng màu sắc/typography của hệ thống.

Kịch bản GiftGenius điển hình minh họa rất tốt cách mọi thứ hoạt động thực tế. Người dùng yêu cầu: “Chọn quà cho bạn với ngân sách đến $50”. ChatGPT khởi chạy GiftGenius, hiển thị các thẻ quà gọn gàng và vài nút ở chế độ inline. Người dùng bấm “Chi tiết” — widget yêu cầu fullscreen và hiển thị bộ lọc, mô tả chi tiết, đánh giá. Khi tiến hành mua hàng, bạn có thể hiển thị một PiP/modal nhỏ với trạng thái “Đang xử lý đơn hàng…”, không che phủ toàn bộ chat.

Mục tiêu của bài giảng này là học cách:

  • hiểu displayMode hiện tại là gì và ứng xử cho phù hợp;
  • chuyển chế độ theo yêu cầu (inline ↔ fullscreen, đôi khi PiP);
  • tôn trọng maxHeight và tránh “cuộn kép”;
  • thích ứng kiểu dáng với chế độ sáng/tối và độ rộng màn hình;
  • xây dựng layout trông “bản địa” bên trong ChatGPT.

2. Các chế độ displayMode: inline, fullscreen, PiP

Bắt đầu với khái niệm. displayMode là trạng thái vùng chứa widget của bạn trong ChatGPT. Nó đến từ nền tảng (qua window.openai.displayMode hoặc hook useDisplayMode) và có thể nhận các giá trị như "inline", "fullscreen", "pip".

Inline

Inline là chế độ mặc định. Widget được chèn trực tiếp vào dòng tin nhắn như một “khối” nữa giữa các câu trả lời văn bản. Chiều rộng bị giới hạn bởi cột chat (trên desktop khoảng ~700–800px, trên điện thoại là chiều rộng màn hình), chiều cao linh hoạt nhưng không vô hạn.

Inline lý tưởng cho:

  • các phần hiển thị ngắn gọn, độc lập: thẻ quà, danh sách tùy chọn, tóm tắt tìm kiếm;
  • một-hai hành động: “Chọn”, “Hủy”, “Hiển thị thêm”.

Với GiftGenius, đây là chế độ chính: người dùng đưa yêu cầu, bạn hiển thị 3–5 thẻ quà kèm nút mà không chiếm toàn bộ màn hình.

Fullscreen (Canvas)

Fullscreen (hay canvas) là chế độ khi widget của bạn chiếm phần lớn vùng hiển thị. Chat không biến mất: ô nhập vẫn có, nhưng sự chú ý chính dồn vào UI của bạn.

Bật fullscreen hữu ích khi:

  • có nhiều ô nhập hoặc quy trình phức tạp (đặt hàng, bộ lọc phức tạp, cài đặt);
  • cần hiển thị bảng lớn, bản đồ, so sánh hàng chục phần tử;
  • inline không còn đủ chỗ và bắt đầu trông như “mini‑Excel” cao 700px.

Với GiftGenius, fullscreen cần để cung cấp bộ lọc đầy đủ, sắp xếp, mô tả chi tiết, có thể có nhiều tab.

PiP / Modal

PiP (picture-in-picture) và modal là các cửa sổ “nổi” nhỏ trên nội dung chính. Trong bản SDK Apps hiện tại, PiP thường được hiện thực hoặc như một chế độ displayMode riêng, hoặc như một cửa sổ modal qua requestModal().

Chúng hữu ích khi:

  • cần hiển thị trạng thái của quy trình dài (xử lý đơn hàng, render video);
  • cần hỏi nhanh thứ gì đó mà không ngắt dòng chính (xác nhận nhanh);
  • bạn muốn người dùng “giữ widget trong tầm mắt” trong khi tiếp tục chat.

Trong GiftGenius, đó có thể là bảng nhỏ “Đang đặt hàng… 30%” kèm nút “Hủy”.

So sánh nhanh

Bảng so sánh trực quan:

Chế độ Nằm ở đâu Tình huống điển hình Giới hạn
inline
trong dòng tin nhắn Danh sách, thẻ, một-hai nút Chiều cao hạn chế, chiều rộng hẹp
fullscreen
bên trên/bên cạnh khung chat Trình hướng dẫn, form phức tạp, bảng Cần layout và điều hướng hợp lý
PiP / modal lớp nổi Trạng thái, mini‑form, video Rất ít chỗ, mọi thứ cần lớn và đơn giản

Điều quan trọng là đừng coi fullscreen là “ứng dụng thật”, còn inline là “preview”. Đây là cùng một App, chỉ ở những “tư thế” khác nhau.

3. Hooks làm việc với chế độ: useDisplayMode, useRequestDisplayMode, useRequestModal

Giờ khi đã hiểu inline/fullscreen/PiP là gì về mặt UX, hãy xem cách làm việc với chúng trong code qua các hook của Apps SDK.

Thay vì đọc window.openai.displayMode trực tiếp, ta dùng hook từ template, hook này lắng nghe thay đổi và giúp bạn tránh các nghi thức xử lý sự kiện SDK thủ công. Interface điển hình:

// kiểu giả, hãy kiểm tra tên thực tế theo template
type DisplayMode = 'inline' | 'fullscreen' | 'pip';

function useDisplayMode() {
  // trả về chế độ hiện tại
  return { displayMode: 'inline' as DisplayMode };
}

function useRequestDisplayMode() {
  // hàm yêu cầu đổi chế độ
  return {
    requestDisplayMode: (mode: DisplayMode) => {
      /* gọi window.openai.requestDisplayMode */
    },
  };
}

Hãy làm một component đơn giản hiển thị chế độ hiện tại và cung cấp nút “Mở rộng / Thu gọn”:

import { useDisplayMode, useRequestDisplayMode } from '@/apps-sdk';

export function DisplayModeDebug() {
  const { displayMode } = useDisplayMode();
  const { requestDisplayMode } = useRequestDisplayMode();

  const toggle = () => {
    requestDisplayMode(displayMode === 'inline' ? 'fullscreen' : 'inline');
  };

  return (
    <div className="text-xs text-gray-500 flex gap-2 items-center">
      <span>Chế độ: {displayMode}</span>
      <button onClick={toggle} className="underline">
        Chuyển
      </button>
    </div>
  );
}

Trong App thực tế bạn thường ẩn các phần “debug” như vậy, nhưng ở Dev Mode, component này giúp bạn cảm nhận rõ widget ứng xử ra sao khi chuyển chế độ.

Inline vs Fullscreen bằng các tiểu component khác nhau

Lỗi phổ biến — cố dùng một layout duy nhất cho mọi chế độ và nhét vào JSX một đống if (displayMode === ...). Dễ hiểu hơn là tách giao diện:

import { useDisplayMode } from '@/apps-sdk';
import { GiftListInline } from './GiftListInline';
import { GiftListFullscreen } from './GiftListFullscreen';

export function GiftWidget() {
  const { displayMode } = useDisplayMode();

  if (displayMode === 'fullscreen') {
    return <GiftListFullscreen />;
  }

  return <GiftListInline />;
}

Như vậy, code được đọc là “nếu fullscreen — đây là trình hướng dẫn phức tạp; còn lại — inline gọn nhẹ”. Mỗi tiểu component có thể được style riêng theo giới hạn của mình. Cách tiếp cận này cũng là khuyến nghị trong module: tách chế độ thành các tiểu component thay vì một if/else khổng lồ.

Modal: useRequestModal

Nếu template có hook useRequestModal, interface thường như sau:

const { requestModal } = useRequestModal();
// requestModal({ title }) hoặc tương tự vậy.

Modal khá giống fullscreen nhưng không thay thế cho fullscreen: fullscreen dành cho kịch bản lớn, modal dành cho một bước ngắn (xác nhận hành động, nhập mã giảm giá, v.v.).

4. Kiểm soát kích thước: maxHeight, cuộn và notifyIntrinsicHeight()

Yếu tố quan trọng thứ hai — chiều cao. Nền tảng nói với widget: “Đây là chiều cao tối đa khả dụng”. Giới hạn này có thể đọc từ window.openai.maxHeight hoặc qua hook useMaxHeight.

Tại sao không thể đặt “height: 5000px”

Nếu bạn bỏ qua maxHeight và đặt chiều cao cố định khổng lồ, ChatGPT sẽ buộc phải cắt nội dung. Hoặc nó sẽ đưa cho người dùng cuộn kép: cuộn bên ngoài của chat và cuộn bên trong của widget. Đây là UX tệ: người dùng phải đoán cuộn ở đâu để tới được nút cần thiết.

Chiến lược đúng là:

  1. Đọc giới hạn maxHeight.
  2. Xây layout sao cho cuộn chính vẫn thuộc về khung chat (đặc biệt ở inline).
  3. Ở fullscreen có thể chấp nhận một chút cuộn nội bộ, nhưng cần thận trọng.

useMaxHeight và giới hạn vùng chứa

Hãy viết một wrapper đơn giản đặt giới hạn tối đa theo chiều cao cho vùng chứa gốc:

import { useMaxHeight } from '@/apps-sdk';

export function WidgetContainer(props: { children: React.ReactNode }) {
  const { maxHeight } = useMaxHeight(); // ví dụ 600

  return (
    <div
      style={{ maxHeight }}
      className="overflow-y-auto p-4 bg-background border border-border rounded-xl"
    >
      {props.children}
    </div>
  );
}

Ở đây ta giới hạn chiều cao một cách trung thực và bật cuộn dọc bên trong vùng chứa nhưng ở mức hợp lý. Trên thực tế, ở inline nên tránh cuộn nội bộ lớn — thay vào đó hiển thị một phần dữ liệu với nút “Hiển thị thêm” hoặc gợi ý chuyển sang fullscreen.

Chiều cao động và notifyIntrinsicHeight()

Một lưu ý khác: nội dung của bạn có thể thay đổi kích thước theo thời gian. Ví dụ, lúc đầu hiển thị spinner “Đang tải quà…”, sau đó là danh sách 10 thẻ, rồi người dùng thu gọn/mở rộng bộ lọc. Để ChatGPT cấp phát vùng chứa đúng và không cắt bớt, khi chiều cao thay đổi, bạn cần thông báo giá trị mới cho host. Dùng notifyIntrinsicHeight() cho việc này.

Trong template, điều này thường được bọc trong hook như useAutoResize. Có thể hiện thực như sau:

import { useEffect, useRef } from 'react';
import { useNotifyIntrinsicHeight } from '@/apps-sdk';

export function useAutoResize() {
  const ref = useRef<HTMLDivElement | null>(null);
  const { notifyIntrinsicHeight } = useNotifyIntrinsicHeight();

  useEffect(() => {
    if (!ref.current) return;

    const observer = new ResizeObserver(entries => {
      for (const entry of entries) {
        notifyIntrinsicHeight(entry.contentRect.height);
      }
    });

    observer.observe(ref.current);
    return () => observer.disconnect();
  }, [notifyIntrinsicHeight]);

  return ref;
}

Và sử dụng:

export function GiftListInline() {
  const containerRef = useAutoResize();

  return (
    <div ref={containerRef}>
      {/* nội dung của bạn */}
    </div>
  );
}

Ý tưởng đơn giản: khi div gốc của bạn thay đổi chiều cao, bạn gọi API SDK và ChatGPT điều chỉnh vùng chứa. Mẫu này được các nhà phát triển giàu kinh nghiệm khuyên dùng: “wrapper tự co giãn” bao quanh toàn bộ nội dung.

Sơ đồ nhỏ

Hình dung dưới dạng lưu đồ:

flowchart TD
    A[Nội dung widget thay đổi] --> B[ResizeObserver ghi nhận chiều cao mới]
    B --> C["Gọi notifyIntrinsicHeight(newHeight)"]
    C --> D[ChatGPT tăng/giảm kích thước vùng chứa]
    D --> E[Người dùng thấy cuộn mượt, không bị cắt]

Vậy là xong phần kích thước và chiều cao: widget không nên vượt quá không gian được cấp và không tạo “bài toán hai thanh cuộn” cho người dùng.

5. Chủ đề (theme), màu sắc và viền: làm widget trông “bản địa”

Nếu displayModemaxHeight quyết định bao nhiêu không gian ta có, thì chủ đề (theme) và bảng màu quyết định cách phần giao diện đó xuất hiện trong chat.

ChatGPT hỗ trợ tối thiểu hai chế độ sáng và tối. Nền tảng truyền thông tin này vào widget qua window.openai.theme và/hoặc trong _meta["openai/theme"], và trong React template có hook useOpenAiGlobal("theme") hoặc useTheme tương tự.

Ý chính: UI của bạn nên thích ứng với theme, không áp đặt theme riêng.

Lấy chủ đề

Ví dụ một hook đơn giản:

import { useOpenAiGlobal } from '@/apps-sdk';

export function useThemeMode() {
  const theme = useOpenAiGlobal<'light' | 'dark'>('theme') ?? 'light';
  return { theme };
}

Trong component:

export function ThemedCard(props: { children: React.ReactNode }) {
  const { theme } = useThemeMode();

  const className =
    theme === 'dark'
      ? 'bg-slate-900 text-slate-100 border-slate-700'
      : 'bg-white text-slate-900 border-slate-200';

  return (
    <div className={`rounded-xl border p-4 ${className}`}>
      {props.children}
    </div>
  );
}

Trong dự án thực tế, bạn có thể dùng Tailwind với darkMode: 'class' và gắn class dark vào vùng chứa gốc của widget. Nhưng bản chất không đổi: theme đến từ Apps SDK, không “tự phát”.

Màu sắc, viền và typography

Theo hướng dẫn của OpenAI:

  • dùng font hệ thống và typography gọn gàng;
  • không ghi đè màu hệ thống một cách mạnh tay;
  • widget nên là phần “bản địa” của khung chat, không phải một landing rực rỡ màu mè.

Một pattern tốt cho vùng chứa GiftGenius:

export function GiftCard(props: { title: string; price: string }) {
  return (
    <div className="rounded-xl border border-border bg-background p-3 flex flex-col gap-2">
      <div className="font-medium text-foreground">{props.title}</div>
      <div className="text-sm text-muted-foreground">{props.price}</div>
      <button className="self-start px-3 py-1 text-sm rounded-full bg-primary text-primary-foreground">
        Chọn
      </button>
    </div>
  );
}

Ở đây giả định các class như bg-background, border-border, text-foreground, bg-primary… là các biến CSS/utility class liên kết với theme của ChatGPT. Cách làm này cũng được khuyến nghị: dùng biến và class gắn với theme thay vì hard-code màu sắc.

6. Layout và tính thích ứng: desktop, mobile, PiP

Yếu tố thứ ba — độ rộng và thiết bị. Nói đơn giản, giao diện widget được quyết định bởi chế độ (displayMode), chiều cao khả dụng (maxHeight) và chiều rộng khả dụng (desktop/mobile/PiP).

Phần này bàn về tham số thứ ba. Trên desktop, widget inline có một độ rộng; trên mobile — độ rộng khác; với PiP thì không gian rất ít. Apps SDK cung cấp các tín hiệu như userAgent, safeArea, đôi khi cả kích thước vùng chứa, có thể đọc qua useOpenAiGlobal.

Nguyên tắc chung

Một vài nguyên tắc quan trọng dưới đây.

Thứ nhất, đừng dựa vào chiều rộng cố định. Màn hình người dùng có thể hẹp (điện thoại) hoặc rộng (desktop lớn). Vì vậy, layout nên dựa trên flex/grid với auto-fit thay vì cố định width: 400px.

Thứ hai, tránh cuộn ngang. Nếu bảng hay thẻ của bạn không vừa, tốt hơn là chuyển sang fullscreen hoặc hiển thị phiên bản rút gọn. Cũng có thể dùng carousel nhiều slide.

Thứ ba, lưu ý PiP/modal thường rất hẹp, không thể nhét một form lớn — người dùng sẽ rất khó thao tác.

Những điểm này được nhấn mạnh trong tài liệu: tính thích ứng, safeArea, khác biệt desktop vs mobile và nguy cơ layout quá tải.

Layout khác nhau cho inline và fullscreen

Quay lại GiftGenius. Danh sách quà ở inline và fullscreen có thể khác nhau đáng kể. Hãy làm hai component.

Inline gọn: tối đa 3 thẻ, một cột trên mobile và hai cột trên màn rộng.

export function GiftListInline() {
  const gifts = useGiftData(); // hook giả định, lấy từ toolOutput

  return (
    <WidgetContainer>
      <h2 className="text-base font-semibold mb-3">
        Gợi ý quà tặng
      </h2>

      <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
        {gifts.slice(0, 3).map(gift => (
          <GiftCard
            key={gift.id}
            title={gift.title}
            price={`${gift.price} $`}
          />
        ))}
      </div>

      {gifts.length > 3 && (
        <p className="mt-3 text-xs text-muted-foreground">
          Hiển thị 3 lựa chọn đầu tiên. Mở rộng widget để xem tất cả.
        </p>
      )}
    </WidgetContainer>
  );
}

Và phiên bản fullscreen: lưới, bộ lọc, nhiều thẻ hơn.

export function GiftListFullscreen() {
  const gifts = useGiftData();
  const [query, setQuery] = useState('');

  const filtered = gifts.filter(g =>
    g.title.toLowerCase().includes(query.toLowerCase()),
  );

  return (
    <div className="h-full flex flex-col gap-4 p-4">
      <header className="flex gap-2 items-center">
        <h1 className="text-lg font-semibold flex-1">
          Quà tặng dành cho bạn
        </h1>
        <input
          value={query}
          onChange={e => setQuery(e.target.value)}
          placeholder="Lọc theo tên"
          className="px-2 py-1 text-sm border rounded-md flex-1"
        />
      </header>

      <main className="flex-1 overflow-y-auto">
        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
          {filtered.map(gift => (
            <GiftCard
              key={gift.id}
              title={gift.title}
              price={`${gift.price} $`}
            />
          ))}
        </div>
      </main>
    </div>
  );
}

Ở đây ta cho phép cuộn dọc nội bộ phần nội dung fullscreen (overflow-y-auto trên main), điều này là bình thường với chế độ toàn màn hình. Bản inline, như hướng dẫn khuyến nghị, vẫn gọn gàng và “đọc trong 2 giây”.

Schematic: hành vi theo chế độ

Để củng cố, vẽ sơ đồ đơn giản:

stateDiagram-v2
    [*] --> Inline
    Inline: 3 thẻ, tối thiểu chữ
    Inline --> Fullscreen: Nhấp "Mở rộng" / "Hiển thị tất cả"
    Fullscreen: Lưới, bộ lọc, nhiều dữ liệu
    Fullscreen --> Inline: Nút "Đóng" / hành động của host
    Fullscreen --> PiP: Tác vụ dài, hiển thị tiến trình
    PiP: Bảng trạng thái nhỏ
    PiP --> Inline: Hoàn tất tác vụ, hiển thị thông báo kết quả

Kịch bản này rất giống các pattern UX đã mô tả: inline như teaser, fullscreen là công cụ làm việc, PiP là chỉ báo tiến trình.

7. Thực hành: hai chế độ của cùng một widget

Đến lúc thực hành trong code. Trong phạm vi bài này, hợp lý nhất là làm hai bước trong ứng dụng học tập hiện tại.

Bước 1. Widget inline với thẻ

Mở rộng GiftGenius hiện tại để ở chế độ inline, widget:

  • hiển thị tiêu đề “Gợi ý quà tặng”;
  • hiển thị tối đa ba thẻ quà từ toolOutput;
  • hiển thị gợi ý “Mở rộng widget để xem tất cả” nếu có hơn ba món quà;
  • tự điều chỉnh chiều cao qua useAutoResizenotifyIntrinsicHeight().

Đồng thời, style cần dựa trên theme: dùng class hoặc biến gắn với theme, không hard-code màu.

Bước 2. Phiên bản fullscreen với form

Sau đó thêm giao diện fullscreen, trong đó:

  • hiển thị tiêu đề + ô tìm theo tên;
  • đưa toàn bộ quà vào lưới;
  • cho phép cuộn dọc trong vùng nội dung chính;
  • cung cấp nút “Quay lại hội thoại” (gọi requestDisplayMode('inline')).

Bố cục có thể như sau:

export function GiftGeniusWidget() {
  const { displayMode } = useDisplayMode();

  return (
    <>
      <DisplayModeDebug />
      {displayMode === 'fullscreen' ? (
        <GiftListFullscreen />
      ) : (
        <GiftListInline />
      )}
    </>
  );
}

Trong ChatGPT Dev Mode, bạn có thể chuyển chế độ thủ công hoặc yêu cầu fullscreen bằng code khi bấm nút “Hiển thị tất cả” ở bản inline (qua useRequestDisplayMode). Bài tập này sẽ củng cố hiểu biết về cách một App có thể trông và hành xử khác nhau tùy theo displayMode.

8. Lỗi thường gặp khi quản lý giao diện widget

Trước khi tiếp tục khóa học, cùng chốt vài “cạm bẫy” liên quan đến displayMode, kích thước, theme và layout. Tránh chúng từ đầu sẽ giúp làm việc với Apps SDK dễ chịu hơn nhiều.

Lỗi #1: Bỏ qua displayMode và cố “ép” mọi thứ giống fullscreen.
Đôi khi nhà phát triển vẽ một layout nặng (gần như SPA riêng) vừa khít trong inline. Kết quả là người dùng thấy một Notion tí hon với cuộn và vô số phần tử. Cách đúng — thiết kế các giao diện khác nhau cho các chế độ và tôn trọng việc inline là định dạng gọn, “một màn hình”.

Lỗi #2: Chiều cao cố định khổng lồ và cuộn kép.
Đặt height: 800px và quên maxHeight — con đường dẫn tới việc widget bị cắt hoặc sinh ra cuộn trong/ngoài cùng lúc. Người dùng sẽ phải “bắt đúng thanh cuộn”, làm UX xấu đi. Thay vào đó, hãy đọc maxHeight, giới hạn bằng max-height và khi chiều cao thay đổi thì báo qua notifyIntrinsicHeight().

Lỗi #3: Phớt lờ theme và cố “nhuộm” mọi thứ theo brand.
Nếu bạn áp font riêng, nền riêng, gradient gắt và bỏ qua theme sáng/tối của ChatGPT, bạn phá vỡ sự thống nhất thị giác của nền tảng. Hướng dẫn nêu rõ: dùng màu và font hệ thống, đem bản sắc thương hiệu bằng các điểm nhấn tinh tế (nút, icon, logo). Theo dõi theme qua hook và điều chỉnh bảng màu.

Lỗi #4: UI quá phức tạp trong PiP/modal.
Nhồi cả một form nhiều trường vào PiP nhỏ là bất khả thi. Ở đó chỉ phù hợp các trường hợp rất đơn giản: tiến trình, một-hai nút, một ô nhập. Mọi thứ khác — ứng viên cho fullscreen.

Lỗi #5: Cố định 800px và không test trên mobile.
Cố định 800px và nghĩ “thế nào cũng vừa trên điện thoại”. Thực tế, client ChatGPT trên mobile có độ rộng và hành vi khác, còn PiP thì hẹp hơn. Đừng quên userAgent/safeArea, dùng grid/flex không cố định chiều rộng và ít nhất một lần xem widget ở layout hẹp.

Lỗi #6: Làm việc trực tiếp với window.openai mà không dùng hook.
Về mặt kỹ thuật, bạn có thể viết const mode = window.openai.displayMode, nhưng bạn sẽ phải tự đăng ký sự kiện, nghĩ về cập nhật React và bắt bug nếu SDK thay đổi gì đó. Các hook (useDisplayMode, useMaxHeight, useOpenAiGlobal, useRequestDisplayMode) được tạo ra để ẩn bớt phần việc lặt vặt và giữ code sạch. Tốt hơn hãy dùng chúng cho an tâm.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION