欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何在React中通過URL預(yù)覽Excel文件

 更新時間:2025年03月25日 15:20:24   作者:小堯1  
這篇文章主要為大家詳細(xì)介紹了如何在React中通過URL預(yù)覽Excel文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

在前端開發(fā)中,我們經(jīng)常會遇到需要從遠(yuǎn)程 URL 加載 Excel 文件并展示數(shù)據(jù)的場景。無論是數(shù)據(jù)分析、報表展示還是動態(tài)表格生成,一個高效、易用的解決方案都能大大提升用戶體驗。今天,我將分享一個基于 React 的組件 ExcelPreviewFromURL,教你如何通過 URL 預(yù)覽 Excel 文件,并逐步優(yōu)化代碼,讓它更健壯、更易維護(hù)。無論你是 React 新手還是資深開發(fā)者,這篇文章都會帶給你一些啟發(fā)!

為什么需要從 URL 預(yù)覽 Excel 文件?

想象一下:你的用戶需要從服務(wù)器下載一個 Excel 文件,然后在瀏覽器中快速查看內(nèi)容,而無需手動下載和打開。這種需求在企業(yè)應(yīng)用、數(shù)據(jù)儀表盤或在線工具中非常常見。我們將使用 React、XLSX 庫和 react-table 來實現(xiàn)這一功能,目標(biāo)是:

  • 高效加載:從 URL 獲取 Excel 文件并解析。
  • 動態(tài)展示:將數(shù)據(jù)渲染成表格,支持日期格式優(yōu)化。
  • 用戶友好:提供加載狀態(tài)和錯誤提示。

下面,我們從原始代碼開始,逐步優(yōu)化,并分享實現(xiàn)細(xì)節(jié)。

初始代碼:一個簡單的起點

以下是原始的 React 組件代碼,用于從 URL 加載并預(yù)覽 Excel 文件:

import React, { useState, useEffect } from 'react';
import * as XLSX from 'xlsx';
import { useTable } from 'react-table';
import './ExcelPreviewFromURL.less';

const ExcelPreviewFromURL = ({ fileUrl }) => {
  const [data, setData] = useState([]);
  const [columns, setColumns] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    if (fileUrl) {
      setLoading(true);
      fetch(fileUrl)
        .then(response => {
          if (!response.ok) throw new Error('Failed to fetch Excel file.');
          return response.arrayBuffer();
        })
        .then(data => {
          const workbook = XLSX.read(data, { type: 'array', cellDates: true });
          const sheet = workbook.Sheets[workbook.SheetNames[0]];
          const sheetData = XLSX.utils.sheet_to_json(sheet, { header: 1, raw: false });
          const columns = sheetData[0].map((col, index) => ({
            Header: col,
            accessor: index.toString(),
          }));
          const rowData = sheetData.slice(1).map(row => {
            return row.reduce((acc, curr, colIndex) => {
              acc[colIndex.toString()] = curr;
              return acc;
            }, {});
          });
          setColumns(columns);
          setData(rowData);
          setLoading(false);
        })
        .catch(err => {
          setLoading(false);
          setError('Failed to load Excel file.');
        });
    }
  }, [fileUrl]);

  const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ columns, data });

  if (loading) return <div>Loading...</div>;
  if (error) return <div>{error}</div>;

  return (
    <div className="table-container">
      <table {...getTableProps()} className="excel-table">
        <thead>
          {headerGroups.map((headerGroup, index) => (
            <tr {...headerGroup.getHeaderGroupProps()} key={index}>
              {headerGroup.headers.map((column, index) => (
                <th key={index} {...column.getHeaderProps()}>{column.render('Header')}</th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {rows.map((row, index) => {
            prepareRow(row);
            return (
              <tr key={index} {...row.getRowProps()}>
                {row.cells.map((cell, index) => (
                  <td key={index} {...cell.getCellProps()}>{cell.render('Cell')}</td>
                ))}
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

export default ExcelPreviewFromURL;

這段代碼已經(jīng)能實現(xiàn)基本功能:從 URL 獲取 Excel 文件,解析數(shù)據(jù),并用 react-table 渲染成表格。但它存在一些問題,比如代碼可讀性不高、錯誤處理不夠健壯、日期格式未優(yōu)化等。下面,我們一步步改進(jìn)它。

優(yōu)化代碼:從“好用”到“優(yōu)雅”

1. 類型安全:引入 TypeScript 類型

原始代碼中,any 類型的使用讓代碼缺乏類型約束,容易埋下隱患。我們可以用 TypeScript 定義清晰的類型,提升代碼健壯性:

interface RowData {
  [key: string]: string | number | Date;
}

interface Column {
  Header: string;
  accessor: string;
}

const ExcelPreviewFromURL: React.FC<{ fileUrl: string }> = ({ fileUrl }) => {
  const [data, setData] = useState<RowData[]>([]);
  const [columns, setColumns] = useState<Column[]>([]);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);
  // ...
};

這樣,data、columnserror 的類型更明確,IDE 也能提供更好的提示。

2. 提取邏輯:分離數(shù)據(jù)解析函數(shù)

useEffect 中的邏輯過于復(fù)雜,我們可以提取一個獨立的函數(shù)來處理 Excel 文件的加載和解析:

const parseExcelFromUrl = async (url: string): Promise<{ columns: Column[]; data: RowData[] }> => {
  const response = await fetch(url);
  if (!response.ok) throw new Error('Failed to fetch Excel file.');
  
  const arrayBuffer = await response.arrayBuffer();
  const workbook = XLSX.read(arrayBuffer, { type: 'array', cellDates: true });
  const sheet = workbook.Sheets[workbook.SheetNames[0]];
  const sheetData = XLSX.utils.sheet_to_json(sheet, { header: 1, raw: false }) as string[][];

  const columns = sheetData[0].map((col, index) => ({
    Header: col,
    accessor: index.toString(),
  }));

  const rowData = sheetData.slice(1).map((row, rowIndex) =>
    row.reduce((acc, curr, colIndex) => {
      const cellRef = XLSX.utils.encode_cell({ r: rowIndex + 1, c: colIndex });
      const cell = sheet[cellRef];
      acc[colIndex.toString()] = cell?.t === 'd' ? XLSX.SSF.format('yyyy-mm-dd', cell.v) : curr;
      return acc;
    }, {} as RowData)
  );

  return { columns, data: rowData };
};

然后在 useEffect 中調(diào)用:

useEffect(() => {
  if (!fileUrl) return;

  setLoading(true);
  parseExcelFromUrl(fileUrl)
    .then(({ columns, data }) => {
      setColumns(columns);
      setData(data);
      setLoading(false);
    })
    .catch(err => {
      setError(err.message || 'Failed to load Excel file.');
      setLoading(false);
    });
}, [fileUrl]);

這樣,代碼結(jié)構(gòu)更清晰,邏輯復(fù)用性也更高。

3. 優(yōu)化日期處理:讓數(shù)據(jù)更直觀

原始代碼中,日期處理不夠完善。我們通過 XLSX.SSF.format 將日期格式化為 yyyy-mm-dd,這在解析函數(shù)中已經(jīng)實現(xiàn)。如果需要更多格式(如 MM/DD/YYYY),可以傳入一個參數(shù)來自定義。

4. 提升用戶體驗:加載和錯誤狀態(tài)

簡單的 <div>Loading...</div><div>{error}</div> 顯得單調(diào)。我們可以用更友好的 UI 組件,比如添加加載動畫或錯誤提示框:

if (loading) return <div className="loading-spinner">加載中,請稍候...</div>;
if (error) return <div className="error-message">出錯啦:{error}</div>;

CSS 示例:

.loading-spinner {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100px;
  font-size: 16px;
}

.error-message {
  color: #d32f2f;
  padding: 10px;
  border: 1px solid #d32f2f;
  border-radius: 4px;
}

5. 性能優(yōu)化:useMemo 緩存表格配置

react-tableuseTable 每次渲染都會重新計算。我們可以用 useMemo 緩存 columnsdata,減少不必要的計算:

const tableInstance = useTable({
  columns: useMemo(() => columns, [columns]),
  data: useMemo(() => data, [data]),
});

const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = tableInstance;

最終代碼:優(yōu)雅與實用的結(jié)合

以下是優(yōu)化后的完整代碼:

import React, { useState, useEffect, useMemo } from 'react';
import * as XLSX from 'xlsx';
import { useTable } from 'react-table';
import './ExcelPreviewFromURL.less';

interface RowData { [key: string]: string | number | Date; }
interface Column { Header: string; accessor: string; }

const parseExcelFromUrl = async (url: string): Promise<{ columns: Column[]; data: RowData[] }> => {
  const response = await fetch(url);
  if (!response.ok) throw new Error('Failed to fetch Excel file.');
  const arrayBuffer = await response.arrayBuffer();
  const workbook = XLSX.read(arrayBuffer, { type: 'array', cellDates: true });
  const sheet = workbook.Sheets[workbook.SheetNames[0]];
  const sheetData = XLSX.utils.sheet_to_json(sheet, { header: 1, raw: false }) as string[][];

  const columns = sheetData[0].map((col, index) => ({ Header: col, accessor: index.toString() }));
  const rowData = sheetData.slice(1).map((row, rowIndex) =>
    row.reduce((acc, curr, colIndex) => {
      const cellRef = XLSX.utils.encode_cell({ r: rowIndex + 1, c: colIndex });
      const cell = sheet[cellRef];
      acc[colIndex.toString()] = cell?.t === 'd' ? XLSX.SSF.format('yyyy-mm-dd', cell.v) : curr;
      return acc;
    }, {} as RowData)
  );

  return { columns, data: rowData };
};

const ExcelPreviewFromURL: React.FC<{ fileUrl: string }> = ({ fileUrl }) => {
  const [data, setData] = useState<RowData[]>([]);
  const [columns, setColumns] = useState<Column[]>([]);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (!fileUrl) return;
    setLoading(true);
    parseExcelFromUrl(fileUrl)
      .then(({ columns, data }) => {
        setColumns(columns);
        setData(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message || 'Failed to load Excel file.');
        setLoading(false);
      });
  }, [fileUrl]);

  const tableInstance = useTable({
    columns: useMemo(() => columns, [columns]),
    data: useMemo(() => data, [data]),
  });

  const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = tableInstance;

  if (loading) return <div className="loading-spinner">加載中,請稍候...</div>;
  if (error) return <div className="error-message">出錯啦:{error}</div>;

  return (
    <div className="table-container">
      <table {...getTableProps()} className="excel-table">
        <thead>
          {headerGroups.map((headerGroup, index) => (
            <tr {...headerGroup.getHeaderGroupProps()} key={index}>
              {headerGroup.headers.map((column, index) => (
                <th key={index} {...column.getHeaderProps()}>{column.render('Header')}</th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {rows.map((row, index) => {
            prepareRow(row);
            return (
              <tr key={index} {...row.getRowProps()}>
                {row.cells.map((cell, index) => (
                  <td key={index} {...cell.getCellProps()}>{cell.render('Cell')}</td>
                ))}
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

export default ExcelPreviewFromURL;

應(yīng)用場景與擴(kuò)展

這個組件非常適合以下場景:

  • 數(shù)據(jù)預(yù)覽工具:讓用戶在下載前預(yù)覽 Excel 內(nèi)容。
  • 動態(tài)報表:實時從服務(wù)器加載并展示數(shù)據(jù)。
  • 教育平臺:展示學(xué)生成績或課程表。

想進(jìn)一步擴(kuò)展?試試這些點子:

  • 支持多 sheet:添加下拉菜單切換工作表。
  • 分頁與篩選:集成 react-table 的分頁和過濾功能。
  • 導(dǎo)出功能:添加按鈕將表格導(dǎo)出為 CSV 或 Excel。

總結(jié):從代碼到博客的價值

通過這次優(yōu)化,我們不僅讓代碼更優(yōu)雅、可維護(hù),還提升了用戶體驗和性能。

以上就是如何在React中通過URL預(yù)覽Excel文件的詳細(xì)內(nèi)容,更多關(guān)于React預(yù)覽Excel的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React組件與事件的創(chuàng)建使用教程

    React組件與事件的創(chuàng)建使用教程

    react事件綁定時。this并不會指向當(dāng)前DOM元素。往往使用bind來改變this指向,今天通過本文給大家介紹React事件綁定的方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-02-02
  • 淺談python的函數(shù)知識

    淺談python的函數(shù)知識

    這篇文章主要為大家介紹了python的函數(shù),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-11-11
  • React SSR樣式及SEO的實踐

    React SSR樣式及SEO的實踐

    這篇文章主要介紹了React SSR樣式及SEO的實踐,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-10-10
  • 如何使用React構(gòu)建一個擲骰子的小游戲

    如何使用React構(gòu)建一個擲骰子的小游戲

    這篇文章主要介紹了如何使用React構(gòu)建一個擲骰子的小游戲,本文通過實例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • React中如何使用scss

    React中如何使用scss

    這篇文章主要介紹了React中如何使用scss問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • React?Hooks鉤子中API的使用示例分析

    React?Hooks鉤子中API的使用示例分析

    在react類組件(class)寫法中,有setState和生命周期對狀態(tài)進(jìn)行管理,但是在函數(shù)組件中不存在這些,故引入hooks(版本:>=16.8),使開發(fā)者在非class的情況下使用更多react特性
    2022-08-08
  • JavaScript中的useRef 和 useState介紹

    JavaScript中的useRef 和 useState介紹

    這篇文章主要給大家分享的是 JavaScript中的useRef 和 useState介紹,下列文章,我們將學(xué)習(xí) useRef 和 useState hook是什么,它們的區(qū)別以及何時使用哪個。 這篇文章中的代碼示例將僅涉及功能組件,但是大多數(shù)差異和用途涵蓋了類和功能組件,需要的朋友可以參考一下
    2021-11-11
  • Zustand介紹與使用 React狀態(tài)管理工具的解決方案

    Zustand介紹與使用 React狀態(tài)管理工具的解決方案

    本文主要介紹了Zustand,一種基于React的狀態(tài)管理庫,Zustand以簡潔易用、靈活性高及最小化原則等特點脫穎而出,旨在提供簡單而強(qiáng)大的狀態(tài)管理功能
    2024-10-10
  • react配置代理setupProxy.js無法訪問v3.0版本問題

    react配置代理setupProxy.js無法訪問v3.0版本問題

    這篇文章主要介紹了react配置代理setupProxy.js無法訪問v3.0版本問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 關(guān)于React Native使用axios進(jìn)行網(wǎng)絡(luò)請求的方法

    關(guān)于React Native使用axios進(jìn)行網(wǎng)絡(luò)請求的方法

    axios是一個基于Promise的Http網(wǎng)絡(luò)庫,可運行在瀏覽器端和Node.js中,Vue應(yīng)用的網(wǎng)絡(luò)請求基本都是使用它完成的。這篇文章主要介紹了React Native使用axios進(jìn)行網(wǎng)絡(luò)請求,需要的朋友可以參考下
    2021-08-08

最新評論