如何在 Material UI 的自動完成元件中處理非同步請求?


現代 Web 應用程式經常使用自動完成元件,允許使用者在鍵入時從選項列表中搜索和選擇選項。流行的 UI 框架 Material UI 提供了一個強大的自動完成元件,可以增強使用者體驗。在非同步獲取自動完成資料的情況下,有效地處理請求變得至關重要。

本文將探討如何使用 Material UI 在自動完成元件中處理非同步請求,以確保無縫的使用者體驗。

什麼是非同步請求?

在後續連線中,非同步響應會發送回客戶端,允許它傳送新的請求,而無需在等待響應時阻塞。閘道器預設情況下始終傳送同步響應。如果您想要非同步響應,則需要執行一些額外的步驟。

在自動完成元件中,非同步請求在處理大型資料集或從第三方 API 獲取資訊時至關重要。非同步方法確保在整個資料檢索過程中使用者介面保持響應,避免任何應用程式延遲或凍結。

自動完成元件中的非同步請求

自動完成元件可以透過兩種不同的用例處理非同步請求,如下所述:

  • 開啟時載入 - 第一個用例是在開啟時載入,只要網路請求處於掛起狀態,就會顯示進度狀態。它會在載入選項之前等待與元件的互動。

  • 邊輸入邊搜尋 - 第二個用例涉及邊輸入邊搜尋,在每次按鍵時都會發送一個新的請求。如果您的邏輯涉及在每次按鍵時檢索新選項並使用文字框的當前值過濾伺服器,請考慮對請求進行節流。

    還必須透過覆蓋 filterOptions 屬性來關閉自動完成元件的內建過濾功能:

<Autocomplete filterOptions={(x) => x} />

現在讓我們進一步瞭解在 Material UI React 中的自動完成元件中處理非同步請求的完整步驟。

在自動完成元件中處理非同步請求的步驟

步驟 1:建立一個新的 React 應用程式專案

為了使每個自動完成元件都能正常工作,我們需要一個 React 應用程式來執行。要建立一個新的 React 應用程式,請遵循以下命令:

npx create-react-app mynewproject
cd mynewproject

步驟 2:安裝 Material UI 及其所需的模組

建立 React 應用程式後,現在讓我們使用以下命令安裝 Material UI 及其所需的依賴項:

npm install @mui/material @emotion/react @emotion/styled

步驟 3:匯入自動完成元件

要將元件匯入 React 主元件,如下所示:

import React from 'react';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';

步驟 4:新增延遲函式

為了處理非同步請求,我們將首先建立一個延遲休眠函式,該函式返回一個在指定時間後解析的 Promise。

function delSleep(delay = 0) {
   return new Promise((resolve) => {
      setTimeout(resolve, delay);
   });
}

步驟 5:控制自動完成元件

const [autoOpen, setAutoOpen] = useState(false);
const [opData, setOpData] = useState([]);
const load = open && options.length === 0;

//the below fetches options only when Autocomplete is open
useEffect(() => {
   let active = true;

   if (!load) {
      return undefined;
   }

   (async () => {
      await sleep(1e3);

      if (active) {
         setOpData([...yourData]);
      }
   })();

   return () => {
      active = false;
   };
}, [load]);

步驟 6:在自動完成元件中渲染非同步請求

以下是使用已定義的變數和 useEffect 渲染非同步請求的程式碼:

<Autocomplete
   open={autoOpen}
   onOpen={() => {
      setAutoOpen(true);
   }}
   onClose={() => {
      setAutoOpen(false);
   }}
   isOptionEqualToValue={(opData, value) => opData.label === value.label}
   getOptionLabel={(opData) => opData.label}
   options={opData}
   loading={load}
   renderInput={(params) => (
      <TextField
         InputProps={{
            ...params.InputProps,
            endAdornment: (
               <div>
                  {load ? <CircularProgress  /> : null}
                  {params.InputProps.endAdornment}
               </div>
            ),
         }}
      />
   )}
/>

示例 1

以下示例演示了在自動完成元件中處理非同步請求的使用方法。在這裡,當用戶開啟自動完成元件時,只要網路請求處於掛起狀態,就會顯示進度狀態,以顯示資料或來自資料列表陣列的可用選項。

import React, { useEffect, useState } from "react";
import TextField from "@mui/material/TextField";
import Autocomplete from "@mui/material/Autocomplete";
import CircularProgress from "@mui/material/CircularProgress";

const data = [
   { label: "Java language" },
   { label: "Python language" },
   { label: "C++ language" },
   { label: "C language" },
   { label: "Go language" },
   { label: "JavaScript language" },
   { label: "SQL" },
   { label: "MySQL" },
   { label: "HTML" },
   { label: "CSS" },
   { label: "Nextjs " },
   { label: "ReactJS " },
   { label: "VueJS " },
   { label: "Angular " },
   { label: "Angular JS " },
   { label: "PHP language" },
   { label: "R language" },
   { label: "Objective C language" },
   { label: "Cobol language" },
   { label: "Perl language" },
   { label: "Pascal language" },
   { label: "LISP language" },
   { label: "Fortran language" },
   { label: "Swift language" },
   { label: "Ruby language" },
   { label: "Algol language" },
   { label: "Scala language" },
   { label: "Rust language" },
   { label: "TypeScript language" },
   { label: "Dart language" },
   { label: "Matlab language" },
   { label: "Ada language" },
   { label: ".NET language" },
   { label: "Bash language" },
];

function delaySleep(delay = 0) {
   return new Promise((resolve) => {
      setTimeout(resolve, delay);
   });
}

export default function App() {
   const [open, setOpen] = useState(false);
   const [dataOptions, setDataOptions] = useState([]);
   const load = open && dataOptions.length === 0;

   useEffect(() => {
      let active = true;

      if (!load) {
         return undefined;
      }

      (async () => {
         await delaySleep(1e3); // For demo purposes.

         if (active) {
            setDataOptions([...data]);
         }
      })();

      return () => {
         active = false;
      };
   }, [load]);

   useEffect(() => {
      if (!open) {
         setDataOptions([]);
      }
   }, [open]);

   return (
      <div
         style={{
            display: "flex",
            marginTop: 30,
            flexDirection: "column",
            alignItems: "center",
            justifyContent: "center",
         }}>
         <Autocomplete
            sx={{ width: 400 }}
            open={open}
            onOpen={() => {
               setOpen(true);
            }}
            onClose={() => {
               setOpen(false);
            }}
            getOptionLabel={(option) => option.label}
            isOptionEqualToValue={(option, value) => option.label === value.label}
            loading={load}
            options={dataOptions}
            renderInput={(params) => ( //render the Textfield with the data options
               <TextField
                  {...params}
                  label="Search your favourite programming language"
                  InputProps={{
                     ...params.InputProps,
                     endAdornment: (
                        <div>
                           {load ? (
                              <CircularProgress color="primary" size={30} />
                           ) : null}
                           {params.InputProps.endAdornment}
                        </div>
                     ),
                  }}
               />
            )}
         />
      </div>
   );
}

輸出

示例 2

以下示例演示了在自動完成元件中處理非同步請求的使用方法。在這裡,當用戶鍵入任何關鍵字時,它會在每次按鍵時獲取新的選項,並使用文字框的當前值在伺服器上進行過濾。

import React, { useEffect, useState } from "react";
import TextField from "@mui/material/TextField";
import Autocomplete from "@mui/material/Autocomplete";
import CircularProgress from "@mui/material/CircularProgress";

const data = [
   { label: "Java language" },
   { label: "Python language" },
   { label: "C++ language" },
   { label: "C language" },
   { label: "Go language" },
   { label: "JavaScript language" },
   { label: "SQL" },
   { label: "MySQL" },
   { label: "HTML" },
   { label: "CSS" },
   { label: "Nextjs " },
   { label: "ReactJS " },
   { label: "VueJS " },
   { label: "Angular " },
   { label: "Angular JS " },
   { label: "PHP language" },
   { label: "R language" },
   { label: "Objective C language" },
   { label: "Cobol language" },
   { label: "Perl language" },
   { label: "Pascal language" },
   { label: "LISP language" },
   { label: "Fortran language" },
   { label: "Swift language" },
   { label: "Ruby language" },
   { label: "Algol language" },
   { label: "Scala language" },
   { label: "Rust language" },
   { label: "TypeScript language" },
   { label: "Dart language" },
   { label: "Matlab language" },
   { label: "Ada language" },
   { label: ".NET language" },
   { label: "Bash language" },
];

function delaySleep(delay = 0) {
   return new Promise((resolve) => {
      setTimeout(resolve, delay);
   });
}

export default function App() {
   const [open, setOpen] = useState(false);
   const [dataOptions, setDataOptions] = useState([]);
   const load = open && dataOptions.length === 0;

   useEffect(() => {
      let active = true;

      if (!load) {
         return undefined;
      }

      (async () => {
         await delaySleep(1e3); // For demo purposes.

         if (active) {
            setDataOptions([...data]);
         }
      })();

      return () => {
         active = false;
      };
   }, [load]);

   useEffect(() => {
      if (!open) {
         setDataOptions([]);
      }
   }, [open]);

   return (
      <div
         style={{
            display: "flex",
            marginTop: 30,
            flexDirection: "column",
            alignItems: "center",
            justifyContent: "center",
         }}>
         <Autocomplete
            sx={{ width: 400 }}
            open={open}
            onOpen={() => {
               setOpen(true);
            }}
            onClose={() => {
               setOpen(false);
            }}
            filterOptions={(dataOptions, { inputValue }) => {
               const inputValueLowerCase = inputValue.toLowerCase();
               return dataOptions.filter((option) =>
                  option.label.toLowerCase().includes(inputValueLowerCase)
               );
            }}
            getOptionLabel={(option) => option.label}
            isOptionEqualToValue={(option, value) => option.label === value.label}
            loading={load}
            options={dataOptions}
            renderInput={(params) => ( //render the Textfield with the data options
               <TextField
                  {...params}
                  label="Search your favourite programming language"
                  InputProps={{
                     ...params.InputProps,
                     endAdornment: (
                        <div>
                           {load ? (
                              <CircularProgress color="primary" size={30} />
                           ) : null}
                           {params.InputProps.endAdornment}
                        </div>
                     ),
                  }}
               />
            )}
         />
      </div>
   );
}

輸出

更新時間: 2023年10月30日

1K+ 次檢視

開啟你的 職業生涯

透過完成課程獲得認證

立即開始
廣告