跳到主要內容
+

自訂插槽和子組件

了解如何覆寫 MUI X 組件的部分。

什麼是插槽?

插槽是組件的一部分,可以被覆寫和/或自訂

其中一些插槽允許您為 MUI X 組件提供自己的 UI 基礎元件。這是 Data Grid 組件上所有 baseXXX 組件 (baseButton, baseSelect, ...) 的作用。這些插槽接收的 props 應該盡可能通用,以便於與任何其他設計系統介接。

其他插槽允許您使用專為此組件構建的自訂 UI 來覆寫 MUI X UI 組件的部分。這是 DateCalendar 組件上的 calendarHeader 插槽或 Rich Tree View 組件上的 item 插槽的作用。這些插槽接收特定於 UI 這部分的 props,並且很可能不會在您的應用程式中重複使用。

基本用法

如何覆寫插槽?

您可以通過將自訂組件提供給 slots prop 來覆寫插槽

按下 Enter 鍵開始編輯

如何自訂插槽?

您可以使用 slotProps prop 將 props 傳遞給任何插槽

按下 Enter 鍵開始編輯

您也可以在同一個組件上同時使用 slotsslotProps

按下 Enter 鍵開始編輯

大多數插槽也支援 slotProps 的回呼版本。此回呼接收一個物件,其中包含有關組件目前狀態的資訊,該資訊可能因所使用的插槽而異

按下 Enter 鍵開始編輯

正確用法

插槽是一個 React 組件;因此,它應該在兩次渲染之間保持相同的 JavaScript 參考。如果組件的 JavaScript 參考在兩次渲染之間發生變化,React 將重新掛載它。您可以通過不在 slots prop 中內聯組件定義來避免這種情況。

以下的前兩個範例有錯誤,因為日曆標頭會在每次按鍵後重新掛載,導致焦點丟失。

// ❌ The `calendarHeader` slot is re-defined each time the parent component renders,
// causing the component to remount.
function MyApp() {
  const [name, setName] = React.useState('');
  return (
    <DateCalendar
      slots={{
        calendarHeader: () => (
          <input value={name} onChange={(event) => setName(event.target.value)} />
        ),
      }}
    />
  );
}
// ❌ The `calendarHeader` slot is re-defined each time `name` is updated,
// causing the component to remount.
function MyApp() {
  const [name, setName] = React.useState('');

  const CustomCalendarHeader = React.useCallback(
    () => <input value={name} onChange={(event) => setName(event.target.value)} />,
    [name],
  );

  return <DateCalendar slots={{ calendarHeader: CustomCalendarHeader }} />;
}
// ✅ The `calendarHeader` slot is defined only once, it will never remount.
const CustomCalendarHeader = ({ name, setName }) => (
  <input value={name} onChange={(event) => setName(event.target.value)} />
);

function MyApp() {
  const [name, setName] = React.useState('');
  return (
    <DateCalendar
      slots={{ calendarHeader: CustomCalendarHeader }}
      slotProps={{ calendarHeader: { name, setName } }}
    />
  );
}

TypeScript 的用法

類型自訂插槽

如果您想確保自訂插槽組件的類型安全,可以使用 PropsFromSlot 介面宣告您的組件

function CustomCalendarHeader({
  currentMonth,
}: PropsFromSlot<DateCalendarSlots<Dayjs>['calendarHeader']>) {
  return <div>{currentMonth?.format('MM-DD-YYYY')}</div>;
}

使用額外的 props

如果您要將額外的 props 傳遞給您的插槽,您可以將它們添加到您的自訂組件接收的 props 中

interface CustomCalendarHeaderProps
  extends PropsFromSlot<DateCalendarSlots<Dayjs>['calendarHeader']> {
  displayWeekNumber: boolean;
  setDisplayWeekNumber: (displayWeekNumber: boolean) => void;
}

然後您可以在您的自訂組件中使用這些 props,並存取主機組件提供的 props 和您添加的 props

function CustomCalendarHeader({
  displayWeekNumber,
  setDisplayWeekNumber,
  ...other
}: CustomCalendarHeaderProps) {
  return (
    <Stack>
      <DisplayWeekNumberToggle
        value={displayWeekNumber}
        onChange={setDisplayWeekNumber}
      />
      <PickersCalendarHeader {...other} />
    </Stack>
  );
}

如果您的自訂組件的類型與預設類型不同,您將需要將其轉換為正確的類型。如果您使用 slotProps 將額外的 props 傳遞給您的自訂組件,則可能會發生這種情況。如果我們以 calendarHeader 插槽為例,您可以如下所示轉換您的自訂組件

function MyApp() {
  const [displayWeekNumber, setDisplayWeekNumber] = React.useState(false);
  return (
    <DateCalendar
      displayWeekNumber={displayWeekNumber}
      slots={{
        calendarHeader:
          CustomCalendarHeader as DateCalendarSlots<Dayjs>['calendarHeader'],
      }}
      slotProps={{
        calendarHeader: {
          displayWeekNumber,
          setDisplayWeekNumber,
        } as DateCalendarSlotProps<Dayjs>['calendarHeader'],
      }}
    />
  );
}

使用模組擴充

如果您正在使用 Data Grid 套件之一,您也可以使用模組擴充讓 TypeScript 知道您的自訂 props

declare module '@mui/x-data-grid' {
  interface ToolbarPropsOverrides {
    name: string;
    setName: (name: string) => void;
  }
}

然後您可以使用您的自訂插槽,而無需任何類型轉換

function CustomToolbar({ name, setName }: PropsFromSlot<GridSlots['toolbar']>) {
  return <input value={name} onChange={(event) => setName(event.target.value)} />;
}

function MyApp() {
  const [name, setName] = React.useState('');
  return (
    <DataGrid
      rows={[]}
      columns={[]}
      slots={{ toolbar: CustomToolbar }}
      slotProps={{
        toolbar: { name, setName },
      }}
    />
  );
}

有關更多詳細信息,請參閱Data Grid - 自訂插槽和子組件—使用 TypeScript 的自訂插槽 props

X 組件的插槽

您可以在每個組件的 API 文件中找到插槽列表(例如DataGridDatePickerBarChartRichTreeView)。

大多數插槽都有獨立的文件範例來展示如何使用它們