React-window: Menggunakan elemen tabel html

Dibuat pada 21 Sep 2018  ·  34Komentar  ·  Sumber: bvaughn/react-window

Apakah Anda memiliki contoh penggunaan ini dengan tabel? Saya mencoba untuk membuatnya bekerja tetapi saya memiliki kecurigaan yang kuat bahwa itu tidak berhasil, atau bahwa saya melakukan sesuatu yang sangat salah.
Saya telah menyetel outerTagName menjadi "table" dan innerTagName menjadi "tbody", tetapi saya tidak mendapatkan scrolling apa pun.

Ini kode saya, tidak yakin apakah itu membantu (item adalah daftar objek):

 <List
            outerRef={this._list}
            outerTagName="table"
            innerTagName="tbody"
            height={300}
            itemData={items}
            itemSize={() => 30}
            itemCount={items.length}
            itemKey={item => item.uniqueId}>
            {({index, style, data}) => {
              return (
                <tr style={style} key={index}>
                  <td>Item {index}</td>
                </tr>
              );
            }}
          </List>
💬 question

Komentar yang paling membantu

@pupudu Saya memuji upaya open source Anda dan

Ternyata saya bisa melakukannya dengan sedikit kode, dan banyak kreativitas. Kode ini cukup sederhana sehingga siapa pun dapat menyalin / menempel dan memperluas sesuai keinginan mereka. @bvaughn setelah mengetahui caranya, ini akan sangat mudah untuk ditambahkan ke perpustakaan jika Anda mau, tetapi juga sangat sepele untuk diganti jika Anda tahu caranya.

Singkatnya :

  • Tangkap gaya "teratas" dari baris pertama setelah rendering
  • Simpan nilai itu di React.Context sehingga kita bisa menyebarkannya
  • Menerapkan nilai ke komponen tabel yang akan dipindahkan, bukan baris itu sendiri
  • Tambahkan slot tambahan untuk hal-hal seperti header dan footer.
  • Ergonomi perpustakaan tidak memungkinkan hal-hal untuk diedarkan dengan rapi, jadi React.Context adalah jagoan untuk mengatasi komunikasi lintas komponen.

Kode Kerja Sandbox: https://codesandbox.io/s/react-window-with-table-elements-d861o

Kode untuk referensi

import React from 'react'
import { useState, useRef, useContext } from 'react'
import { FixedSizeList, FixedSizeListProps } from 'react-window'
import { render } from 'react-dom'

/** Context for cross component communication */
const VirtualTableContext = React.createContext<{
  top: number
  setTop: (top: number) => void
  header: React.ReactNode
  footer: React.ReactNode
}>({
  top: 0,
  setTop: (value: number) => {},
  header: <></>,
  footer: <></>,
})

/** The virtual table. It basically accepts all of the same params as the original FixedSizeList.*/
function VirtualTable({
  row,
  header,
  footer,
  ...rest
}: {
  header?: React.ReactNode
  footer?: React.ReactNode
  row: FixedSizeListProps['children']
} & Omit<FixedSizeListProps, 'children' | 'innerElementType'>) {
  const listRef = useRef<FixedSizeList | null>()
  const [top, setTop] = useState(0)

  return (
    <VirtualTableContext.Provider value={{ top, setTop, header, footer }}>
      <FixedSizeList
        {...rest}
        innerElementType={Inner}
        onItemsRendered={props => {
          const style =
            listRef.current &&
            // @ts-ignore private method access
            listRef.current._getItemStyle(props.overscanStartIndex)
          setTop((style && style.top) || 0)

          // Call the original callback
          rest.onItemsRendered && rest.onItemsRendered(props)
        }}
        ref={el => (listRef.current = el)}
      >
        {row}
      </FixedSizeList>
    </VirtualTableContext.Provider>
  )
}

/** The Row component. This should be a table row, and noted that we don't use the style that regular `react-window` examples pass in.*/
function Row({ index }: { index: number }) {
  return (
    <tr>
      {/** Make sure your table rows are the same height as what you passed into the list... */}
      <td style={{ height: '36px' }}>Row {index}</td>
      <td>Col 2</td>
      <td>Col 3</td>
      <td>Col 4</td>
    </tr>
  )
}

/**
 * The Inner component of the virtual list. This is the "Magic".
 * Capture what would have been the top elements position and apply it to the table.
 * Other than that, render an optional header and footer.
 **/
const Inner = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(
  function Inner({ children, ...rest }, ref) {
    const { header, footer, top } = useContext(VirtualTableContext)
    return (
      <div {...rest} ref={ref}>
        <table style={{ top, position: 'absolute', width: '100%' }}>
          {header}
          <tbody>{children}</tbody>
          {footer}
        </table>
      </div>
    )
  }
)

/**
 * Render Our Example
 **/
render(
  <VirtualTable
    height={300}
    width="100%"
    itemCount={1000}
    itemSize={36}
    header={
      <thead>
        <tr>
          <th>Index</th>
          <th>Header 2</th>
          <th>Header 3</th>
          <th>Header 4</th>
        </tr>
      </thead>
    }
    row={Row}
    footer={
      <tfoot>
        <tr>
          <td>Footer 1</td>
          <td>Footer 2</td>
          <td>Footer 3</td>
          <td>Footer 4</td>
        </tr>
      </tfoot>
    }
  />,
  document.querySelector('main')
)

Semua 34 komentar

Saya tidak berpikir ini akan benar-benar berhasil. Sepengetahuan saya, HTMLTableElement tidak benar-benar mendukung overflow seperti yang dibutuhkan komponen windowing. Anda _dapat_ mengubah gaya menjadi display: block tetapi menurut saya itu masih belum berfungsi dengan baik. ( Ini adalah contohnya .)

Mengapa Anda membutuhkan meja? Saya pikir Anda dapat mencapai tata letak kolom yang sama dengan blok sebaris atau tata letak fleksibel.

Beberapa hal tambahan:

  • Anda tidak menentukan parameter yang dibutuhkan width hingga List
  • Anda tidak perlu menambahkan key ke baris Anda
  • itemSize bisa saja 30 daripada () => 30 (ini akan berkinerja sedikit lebih baik)

Terima kasih atas balasan cepatnya.
Kita telah membahas menulis ulang ke div, tetapi karena ini untuk komponen yang cukup besar yang sudah ada, kita hanya ingin memastikan sebelum memulai penulisan ulang itu. Saya melihat beberapa komentar lain tentang rc-table, jadi saya pikir mungkin itu seharusnya berfungsi.
Bagaimanapun, tidak keberatan menulis ulang, itu seharusnya sepadan menurut saya.

Saya mendapat peringatan React tentang kunci tanpa kunci di baris, yang juga membingungkan saya mengingat saya menyetel itemKey, jadi tidak yakin apa yang terjadi di sana.

Terima kasih

Einar

Pada 21 Sep 2018, pada 16:52, Brian Vaughn [email protected] menulis:

Saya tidak berpikir ini akan benar-benar berhasil. Sepengetahuan saya, HTMLTableElement tidak benar-benar mendukung overflow seperti yang dibutuhkan komponen windowing. Anda dapat mengubah gaya untuk menampilkan: blok tetapi saya masih tidak berpikir itu akan bekerja dengan baik.

Mengapa Anda membutuhkan meja? Saya pikir Anda dapat mencapai tata letak kolom yang sama dengan blok sebaris atau tata letak fleksibel.

Beberapa hal tambahan:

Anda tidak menentukan lebar parameter yang dibutuhkan untuk Daftar
Anda tidak perlu menambahkan kunci ke baris Anda
itemSize hanya bisa 30 daripada () => 30 (ini akan bekerja sedikit lebih baik)
-
Anda menerima ini karena Anda yang mengarang utas ini.
Balas email ini secara langsung, lihat di GitHub, atau nonaktifkan utasnya.

Saya mendapat peringatan React tentang kunci tanpa kunci di baris, yang juga membingungkan saya mengingat saya menyetel itemKey, jadi tidak yakin apa yang terjadi di sana.

Ini tidak diharapkan. Bisakah Anda membagikan kasus repro dengan saya (melalui Code Sandbox)?

Ooh, maaf. Saya harus menambahkan bahwa ini _only_ diharapkan jika fungsi itemKey mengembalikan undefined untuk beberapa item– dalam hal ini perbaikan harus dilakukan untuk fungsi itu.

@bvaughn Saya tidak menemukan sesuatu yang spesifik tentang dukungan overflow sebagai faktor pembatas. Anehnya, saya ingin tahu apa itu. Saya tentu mengerti bahwa mendukung fungsionalitas inti untuk keduanya mungkin membosankan, tetapi sepertinya hanya elemen daftar dasar yang berada di luar pilihan implementor saat ini. Berbicara untuk diri saya sendiri dan siapa saja yang mungkin menggunakan react-window dengan skenario header tetap, alangkah baiknya untuk mendapatkan dukungan tabular yang melekat pada tata letak tabel. Menggunakan display: table memang memerlukan overhead dev "beberapa" dan merupakan tata letak satu kali untuk aplikasi sekitarnya yang mungkin secara tidak sengaja dibuat menggunakan tabel. Saya selalu bisa men-tweak overflow atau properti lain melalui css (saya tetap melakukannya dalam implementasi saat ini). Apakah sebuah prop elementType keluar dari pertanyaan?

@bvaughn Saya tidak menemukan sesuatu yang spesifik tentang dukungan overflow sebagai faktor pembatas.

Mungkin saya tidak menggunakan frase terbaik– tetapi jika Anda melihat Sandbox yang saya tautkan (

Berikut adalah contoh lain yang hanya HTML: lx65871p69

HTMLSelectElement ( <tbody> ) mengabaikan gaya seperti height dan overflow - membuatnya tidak berguna untuk windowing. Anda dapat "memperbaiki" ini dengan mengubah mode tampilan ( display: block ) tetapi ini menggagalkan tujuan penggunaan HTMLTableElement karena merusak perilaku pengaturan ukuran kolom.

Perilaku ukuran kolom itu rusak untuk memulai dengan kasus penggunaan windowing, karena ukurannya bergantung pada konten di kolom (yang akan berubah saat pengguna menggulir).

tetapi itu hanya terlihat seperti elemen daftar dasar adalah semua yang berada di luar pilihan implementor saat ini ... Apakah prop elementType keluar dari pertanyaan?

Anda sudah dapat menentukan jenis tag jika Anda benar-benar ingin ( 2j0z718mwy ) meskipun saya tidak melihat apa yang menguntungkan Anda.

Berbicara untuk diri saya sendiri dan siapa saja yang mungkin menggunakan react-window dengan skenario header tetap, alangkah baiknya untuk mendapatkan dukungan tabular yang melekat pada tata letak tabel.

Menggunakan HTMLTableElement akan bermasalah karena alasan yang saya jelaskan di atas. Jika Anda menginginkan tata letak tabular / kisi dengan tajuk tetap, Anda dapat melakukannya dengan menggunakan salah satu komponen daftar biasa: pk78pvwnkx

Mengapa Anda membutuhkan meja? Saya pikir Anda dapat mencapai tata letak kolom yang sama dengan blok sebaris atau tata letak fleksibel.

Mungkin struktur tabel diperlukan untuk beberapa aksesibilitas (seperti, pembacaan layar yang lebih baik dibandingkan dengan div non-semantik)? Saya menebak di sini.

Dalam hal ini saya akan pergi dengan menimpa gaya tampilan CSS dan gaya lain yang melekat pada elemen tabel.

Pengalaman saya membangun komponen tabel yang kompleks (dengan judul tetap / disematkan dari atas dan kiri, struktur colspan / rowpan yang berbelit-belit, dan model data untuk menggambarkan struktur di belakangnya) sekitar sembilan tahun yang lalu (saat itu kami tidak memiliki React, tidak ada masalah aksesibilitas, dan sejauh yang saya ingat tidak ada virtualisasi) adalah bahwa kolega saya yang bertanggung jawab atas komponen ini mencoba menerapkannya dalam elemen tabel yang tepat, berjuang dengan memaksa tata letak untuk berperilaku dengan cara tertentu, dan kemudian memutuskan untuk mengimplementasikan tata letak tabel dalam JavaScript murni dari benar-benar diposisikan dan div berukuran. Solusi itu bekerja dengan sempurna: tidak ada lompatan tata letak yang aneh, pengguliran halus (bukan per baris / per kolom), dll.

Mungkin struktur tabel diperlukan untuk beberapa aksesibilitas (seperti, pembacaan layar yang lebih baik dibandingkan dengan div non-semantik)? Saya menebak di sini.

Peran Aria dapat digunakan untuk ini 😄

Sangat teliti, terima kasih. Anda baru saja menyelamatkan saya dari lubang kelinci untuk mencoba prototipe yang akan menyelesaikan satu masalah hanya untuk membuat yang lain.

Hai
Saya mencoba menemukan utas yang ada alih-alih membuat yang baru. Saya harap saya di tempat yang baik ...

Adakah cara agar memiliki semacam "colspan" untuk menggabungkan dua sel untuk FixedSizeGrid (mungkin lebih masuk akal dalam konteks saya)?
Pertanyaan ini bergantung pada diskusi lain yang dimulai di sini , tetapi untuk lebih masuk akal, saya lebih suka memposting di sini.

Adakah cara agar memiliki semacam "colspan" untuk menggabungkan dua sel untuk FixedSizeGrid (mungkin lebih masuk akal dalam konteks saya)?

Tidak. Ini tidak didukung.

@einarq @BlaineBradbury @sompylasar Jika Anda masih tertarik, saya berhasil mendapatkan pekerjaan windowing dengan tag tabel. Nyatanya, saya akhirnya membuat jendela reaksi pembungkus perpustakaan. Anda dapat melihat demo langsung di sini: https://window-table.netlify.com/

Alasan mengapa saya menginginkan tag tabel terutama untuk gaya. Mendesain tabel html biasa cukup mudah dengan tw-bootstrap, dan karenanya saya ingin melakukan hal yang sama dengan tabel berjendela.

Saya tergoda untuk memberi tag dan bertanya kepada Brian, tentang apa yang dia pikirkan tentang penerapan ini (Karena dia menyebutkan bahwa tag tabel html tidak akan berfungsi). Tapi dia sudah cukup membantuku. Jadi saya serahkan pada kalian.

Terima kasih.

Itu pendekatan yang menarik @pupudu. Saya tidak tahu apakah akan ada masalah aksesibilitas karena memiliki tag <table> untuk header dan baris, tetapi ide yang rapi sebaliknya.

Saya mencoba menggunakan react-datasheet dengan react-window , pada dasarnya berfungsi:

function sheetRenderer(props) {
  const Row = ({ index, style }) => (
    React.cloneElement(props.children[index], { style })
  );
  return (
    <table className={props.className}>
        <tbody>
          <FixedSizeList
              height={150}
              itemCount={1000}
              itemSize={35}
              width={300}
          >
            {Row}
          </FixedSizeList>
        </tbody>
    </table>
  )
}

export default function EntityTable(props: IEntityTableProps) {
  const initialGrid = useMemo(() => {
    return getTableGridFromCSV(props.entityListCSV);
  }, [props.entityListCSV]);
  const [modifiedGrid, updateModifiedGrid] = useImmer(initialGrid);
  return (
    <ReactDataSheet
      data={modifiedGrid}
      sheetRenderer={sheetRenderer}
      valueRenderer={cell => cell.value}
      onCellsChanged={changes => {
        updateModifiedGrid(draft => {
          changes.forEach(({ cell, row, col, value }) => {
            draft[row][col].value = value || '';
          });
        });
      }}
    />
  );
}

function getTableGridFromCSV(csv: string) {
  return csv.split('\n').map(row =>
    row.split(',').map((cell, index) => {
      if (index === 0) {
        return {
          value: cell,
          forceComponent: true,
          component: <button onClick={() => console.log(cell)}>{cell}</button>,
        };
      }
      if (index === 2) {
        return {
          value: cell,
        };
      }
      return {
        value: cell,
        component: <span>{cell}</span>,
      };
    }),
  );
}

Ini membuat, satu-satunya masalah adalah Warning: validateDOMNesting(...): <tr> cannot appear as a child of <div>. index.js:1437 Warning: validateDOMNesting(...): <div> cannot appear as a child of <tbody>.

Hei, saya mencoba ini dengan React-Table dan menyadari bahwa saya harus menggunakan div daripada elemen tabel. Masalah dengan ini adalah bahwa pustaka gaya seperti material / bootstrap bergantung pada elemen-elemen itu. Jadi lebih banyak pekerjaan untuk mengubah skema tabel saya menjadi div daripada elemen tabel. Apakah mungkin sama sekali untuk menggunakan elemen tabel ke diffs atau apakah saya harus membuat gaya saya sendiri sekarang?

@simkessy Kecuali jika Anda sudah menyadarinya, Anda harus checkout window-table. Ini memungkinkan penggunaan tag tabel html yang memungkinkan kita untuk menggunakan kembali gaya yang ada. Harus diakui bahwa tabelnya tidak semaju react-table.
https://window-table.netlify.com/

@pupudu Saya memuji upaya open source Anda dan

Ternyata saya bisa melakukannya dengan sedikit kode, dan banyak kreativitas. Kode ini cukup sederhana sehingga siapa pun dapat menyalin / menempel dan memperluas sesuai keinginan mereka. @bvaughn setelah mengetahui caranya, ini akan sangat mudah untuk ditambahkan ke perpustakaan jika Anda mau, tetapi juga sangat sepele untuk diganti jika Anda tahu caranya.

Singkatnya :

  • Tangkap gaya "teratas" dari baris pertama setelah rendering
  • Simpan nilai itu di React.Context sehingga kita bisa menyebarkannya
  • Menerapkan nilai ke komponen tabel yang akan dipindahkan, bukan baris itu sendiri
  • Tambahkan slot tambahan untuk hal-hal seperti header dan footer.
  • Ergonomi perpustakaan tidak memungkinkan hal-hal untuk diedarkan dengan rapi, jadi React.Context adalah jagoan untuk mengatasi komunikasi lintas komponen.

Kode Kerja Sandbox: https://codesandbox.io/s/react-window-with-table-elements-d861o

Kode untuk referensi

import React from 'react'
import { useState, useRef, useContext } from 'react'
import { FixedSizeList, FixedSizeListProps } from 'react-window'
import { render } from 'react-dom'

/** Context for cross component communication */
const VirtualTableContext = React.createContext<{
  top: number
  setTop: (top: number) => void
  header: React.ReactNode
  footer: React.ReactNode
}>({
  top: 0,
  setTop: (value: number) => {},
  header: <></>,
  footer: <></>,
})

/** The virtual table. It basically accepts all of the same params as the original FixedSizeList.*/
function VirtualTable({
  row,
  header,
  footer,
  ...rest
}: {
  header?: React.ReactNode
  footer?: React.ReactNode
  row: FixedSizeListProps['children']
} & Omit<FixedSizeListProps, 'children' | 'innerElementType'>) {
  const listRef = useRef<FixedSizeList | null>()
  const [top, setTop] = useState(0)

  return (
    <VirtualTableContext.Provider value={{ top, setTop, header, footer }}>
      <FixedSizeList
        {...rest}
        innerElementType={Inner}
        onItemsRendered={props => {
          const style =
            listRef.current &&
            // @ts-ignore private method access
            listRef.current._getItemStyle(props.overscanStartIndex)
          setTop((style && style.top) || 0)

          // Call the original callback
          rest.onItemsRendered && rest.onItemsRendered(props)
        }}
        ref={el => (listRef.current = el)}
      >
        {row}
      </FixedSizeList>
    </VirtualTableContext.Provider>
  )
}

/** The Row component. This should be a table row, and noted that we don't use the style that regular `react-window` examples pass in.*/
function Row({ index }: { index: number }) {
  return (
    <tr>
      {/** Make sure your table rows are the same height as what you passed into the list... */}
      <td style={{ height: '36px' }}>Row {index}</td>
      <td>Col 2</td>
      <td>Col 3</td>
      <td>Col 4</td>
    </tr>
  )
}

/**
 * The Inner component of the virtual list. This is the "Magic".
 * Capture what would have been the top elements position and apply it to the table.
 * Other than that, render an optional header and footer.
 **/
const Inner = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(
  function Inner({ children, ...rest }, ref) {
    const { header, footer, top } = useContext(VirtualTableContext)
    return (
      <div {...rest} ref={ref}>
        <table style={{ top, position: 'absolute', width: '100%' }}>
          {header}
          <tbody>{children}</tbody>
          {footer}
        </table>
      </div>
    )
  }
)

/**
 * Render Our Example
 **/
render(
  <VirtualTable
    height={300}
    width="100%"
    itemCount={1000}
    itemSize={36}
    header={
      <thead>
        <tr>
          <th>Index</th>
          <th>Header 2</th>
          <th>Header 3</th>
          <th>Header 4</th>
        </tr>
      </thead>
    }
    row={Row}
    footer={
      <tfoot>
        <tr>
          <td>Footer 1</td>
          <td>Footer 2</td>
          <td>Footer 3</td>
          <td>Footer 4</td>
        </tr>
      </tfoot>
    }
  />,
  document.querySelector('main')
)

@jamesmfriedman Suka pendekatannya. Ide yang sangat menarik untuk menggunakan Konteks untuk mencapai ini. Saya suka fakta bahwa Anda hanya membuat satu tabel, tidak seperti dalam pendekatan saya di mana saya membuat dua, satu untuk tajuk dan satu untuk badan. Hal ini telah menyebabkan banyak kebingungan (tidak melihat bahwa tbh datang) pada pengguna window-table.

Saya akan mencoba menggunakan ide-ide ini di meja jendela jika Anda tidak keberatan. Saya pikir tantangan terbesar adalah mencari tahu bagaimana mengukur baris secara otomatis berdasarkan konten (yang merupakan tantangan terbesar dari windo-table setidaknya).

@jamesmfriedman yang terlihat sangat menjanjikan. @bvaughn, apakah Anda memiliki kekhawatiran tentang pendekatan ini?

@jamesmfriedman sepertinya header bergulir ke atas bersama dengan konten. Apakah mungkin membuatnya lengket?

Itu sebenarnya mungkin, dan tidak spesifik untuk implementasi ini. Lakukan saja googling di sekitar header lengket dengan elemen tabel HTML. Saya samar-samar mengingat cara melakukan ini sebenarnya dengan membuat posisi elemen TH menjadi lengket.

@jamesmfriedman terima kasih banyak atas contoh Anda 👍 sangat membantu @marink di sini adalah contoh untuk tajuk lengket https://codesandbox.io/s/react-window-with-table-elements-jj70e Anda perlu menambahkan style={{ position: 'sticky', top: 0 }}> ke tag th

@jamesmfriedman Terima kasih banyak atas contohnya. Saya akan mempertimbangkan untuk menggunakannya. Tapi saya pikir menggunakan top: 0 dan position sticky daripada menghitung ulang top dan memiliki posisi absolut pada elemen tabel akan menjadi cara yang tepat. Karena jika Anda menggunakan posisi lengket untuk mendapatkan tajuk lengket pada elemen maka semuanya akan kacau pada gulir cepat.

Jadi baris 79 akan menjadi <table style={{ top: 0, position: 'sticky', width: '100%' }}>

Itu juga memperbaiki masalah gulir jika Anda terus menggulir saat Anda berada di bagian bawah.

Alasan bagus lainnya untuk menggunakan tabel HTML adalah mendukung IE11. Saya menggunakan FixedSizeList dan kemudian menatanya dengan CSS-grid. Namun ketika Anda perlu menambahkan fitur lain seperti kolom responsif, kolom dengan ukuran berbeda, dll, dan membuat semuanya bekerja bersama dengan IE11, Anda akan mendapatkan sejumlah besar kode. Sedangkan tabel HTML bekerja secara default tanpa kode.

IE11 bukanlah sesuatu yang harus Anda dukung lagi :)

Setiap pengembang FE menginginkan IE11 mati. Namun sayangnya, ada perusahaan / orang yang terjebak, tidak dapat bergerak karena alasan yang bahkan tidak dapat kita bayangkan. Mudah-mudahan, ini hanya beberapa tahun ke depan. Sampai saat itu, kami perlu mendukung IE11, suka atau tidak suka.

Itu adalah pil yang sulit untuk saya telan juga.

@ olafur164 terima kasih atas perbaikan Anda untuk tajuk lengket yang tidak merusak gulir cepat. Tahukah Anda jika ada cara untuk menjaga tampilan "lengket" karena sekarang ia menggulung baris demi baris dengan lancar?

Izinkan saya berbagi pengalaman saya dengan react-virtualized (bahkan itu halaman masalah react-window ) dan beberapa pustaka UI material yang disebut https://github.com/mbrn/ material-table / issues / 891 # Issuecomment -681986647. Masih ada beberapa masalah seperti masalah gaya dan peringatan validateDOMNesting(...) .

@jamesmfriedman terima kasih banyak atas contoh Anda 👍 sangat membantu @marink di sini adalah contoh untuk tajuk yang lengket. Anda perlu menambahkan style={{ position: 'sticky', top: 0 }}> ke tag th

Hai @JCofman , saya mencoba memperbaiki CSS Anda tetapi tidak berhasil untuk saya. Berikut contoh kode kotak pasir - https://codesandbox.io/s/react-window-with-table-elements-forked-huti6?file=/src/index.tsx : 514-542

Ada dua masalah -

  1. header tidak menempel di bagian atas meskipun memiliki gaya pada tempatnya.
  2. header berkedip / berkedip sambil menggulir dengan berat ke arah atas.
    [Langkah-langkah mereproduksi - gulir 50% ke bawah lalu lakukan gulir cepat ke atas dan amati pergerakan header].

Terima kasih sebelumnya :)

@jamesmfriedman Suka pendekatannya. Ide yang sangat menarik untuk menggunakan Konteks untuk mencapai ini. Saya suka fakta bahwa Anda hanya membuat satu tabel, tidak seperti dalam pendekatan saya di mana saya membuat dua, satu untuk tajuk dan satu untuk badan. Hal ini telah menyebabkan banyak kebingungan (tidak melihat bahwa tbh datang) pada pengguna window-table.

Saya akan mencoba menggunakan ide-ide ini di meja jendela jika Anda tidak keberatan. Saya pikir tantangan terbesar adalah mencari tahu bagaimana mengukur baris secara otomatis berdasarkan konten (yang merupakan tantangan terbesar dari windo-table setidaknya).

Saya akhirnya menemukan solusi yang sangat mirip karena saya menggunakan display: grid dengan display: contents untuk baris, jadi pada dasarnya mengikuti batasan elemen table > tr .

Anda menggunakan konteks + ref untuk memanggil metode internal, namun, ini sama sekali tidak diperlukan karena hal yang sama dapat dilakukan dengan mencari nilai style.top dari anak pertama:

const Inner = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(
  function Inner({ children, ...rest }, ref) {
    const { header, footer } = useContext(VirtualTableContext)
    const {style} = children[0].props;
    return (
      <div {...rest} ref={ref}>
        <table style={style}>
          {header}
          <tbody>{children}</tbody>
          {footer}
        </table>
      </div>
    )
  }
)

Prop gaya diberikan oleh pustaka ketika ia melakukan createElement untuk setiap baris, dan karena komponen Row Anda tidak menetapkan style menjadi tr , Anda tidak menurunkan mereka juga.

Baru-baru ini, saya bertanya-tanya tentang sesuatu seperti ini. Bagaimana jika kita akan memindahkan seluruh badan tabel dengan padding menggunakan elemen semu (setelah / sebelum) melalui properti kustom css 🤔

Misalnya menggunakan react-virtual menjadi https://codesandbox.io/s/poc-react-virtual-table-jyz0m

Saya benar-benar membutuhkan tabel agar saya dapat mencapai UX yang saya inginkan dan tidak puas dengan solusi untuk membuatnya berfungsi dengan react-window .

Saya akhirnya hanya mengekstrak logika virutalization sendiri ke hook dan menerapkannya dengan dua tabel, satu untuk header dan yang kedua untuk konten, mirip dengan apa yang diposting di atas. Perbedaan dalam pendekatan saya adalah bahwa tabel kedua masih memiliki tajuknya di markup tetapi secara visual tersembunyi sehingga tetap dapat diakses, sedangkan tajuk yang pertama ada di sana hanya untuk pengguna yang awas dan secara posisional ditempel .. Berfungsi seperti pesona, dan kode itu jauh lebih sederhana.

Buang saja ke sana kalau-kalau ada yang ingin mencobanya.

@piecyk Itu bagus, sangat mirip dengan bagaimana virtuoso diimplementasikan: https://virtuoso.dev/grouped-by-first-letter/

Saya harus menambahkan bahwa memposisikan seluruh penampung dengan absolute / top berkinerja baik, tetapi menjalankan audit kinerja dengan Chrome saya melihat masalah CLS yang mungkin berdampak pada FPS. Saya rasa dampaknya tidak terlihat, Anda dapat melihat seberapa cepat dan mulusnya pada contoh ini: https://b6udg.csb.app/ (meskipun merupakan container berukuran besar). Namun dengan padding-top / bottom TIDAK ADA CLS!

Saya akan mencobanya sendiri dan mengukur perbedaannya dalam waktu dekat.

@pupudu Saya memuji upaya open source Anda dan

Ternyata saya bisa melakukannya dengan sedikit kode, dan banyak kreativitas. Kode ini cukup sederhana sehingga siapa pun dapat menyalin / menempel dan memperluas sesuai keinginan mereka. @bvaughn setelah mengetahui caranya, ini akan sangat mudah untuk ditambahkan ke perpustakaan jika Anda mau, tetapi juga sangat sepele untuk diganti jika Anda tahu caranya.

_Pendek itu_:

  • Tangkap gaya "teratas" dari baris pertama setelah rendering
  • Simpan nilai itu di React.Context sehingga kita bisa menyebarkannya
  • Menerapkan nilai ke komponen tabel yang akan dipindahkan, bukan baris itu sendiri
  • Tambahkan slot tambahan untuk hal-hal seperti header dan footer.
  • Ergonomi perpustakaan tidak memungkinkan hal-hal untuk diedarkan dengan rapi, jadi React.Context adalah jagoan untuk mengatasi komunikasi lintas komponen.

Kode Kerja Sandbox: https://codesandbox.io/s/react-window-with-table-elements-d861o

Kode untuk referensi

import React from 'react'
import { useState, useRef, useContext } from 'react'
import { FixedSizeList, FixedSizeListProps } from 'react-window'
import { render } from 'react-dom'

/** Context for cross component communication */
const VirtualTableContext = React.createContext<{
  top: number
  setTop: (top: number) => void
  header: React.ReactNode
  footer: React.ReactNode
}>({
  top: 0,
  setTop: (value: number) => {},
  header: <></>,
  footer: <></>,
})

/** The virtual table. It basically accepts all of the same params as the original FixedSizeList.*/
function VirtualTable({
  row,
  header,
  footer,
  ...rest
}: {
  header?: React.ReactNode
  footer?: React.ReactNode
  row: FixedSizeListProps['children']
} & Omit<FixedSizeListProps, 'children' | 'innerElementType'>) {
  const listRef = useRef<FixedSizeList | null>()
  const [top, setTop] = useState(0)

  return (
    <VirtualTableContext.Provider value={{ top, setTop, header, footer }}>
      <FixedSizeList
        {...rest}
        innerElementType={Inner}
        onItemsRendered={props => {
          const style =
            listRef.current &&
            // @ts-ignore private method access
            listRef.current._getItemStyle(props.overscanStartIndex)
          setTop((style && style.top) || 0)

          // Call the original callback
          rest.onItemsRendered && rest.onItemsRendered(props)
        }}
        ref={el => (listRef.current = el)}
      >
        {row}
      </FixedSizeList>
    </VirtualTableContext.Provider>
  )
}

/** The Row component. This should be a table row, and noted that we don't use the style that regular `react-window` examples pass in.*/
function Row({ index }: { index: number }) {
  return (
    <tr>
      {/** Make sure your table rows are the same height as what you passed into the list... */}
      <td style={{ height: '36px' }}>Row {index}</td>
      <td>Col 2</td>
      <td>Col 3</td>
      <td>Col 4</td>
    </tr>
  )
}

/**
 * The Inner component of the virtual list. This is the "Magic".
 * Capture what would have been the top elements position and apply it to the table.
 * Other than that, render an optional header and footer.
 **/
const Inner = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(
  function Inner({ children, ...rest }, ref) {
    const { header, footer, top } = useContext(VirtualTableContext)
    return (
      <div {...rest} ref={ref}>
        <table style={{ top, position: 'absolute', width: '100%' }}>
          {header}
          <tbody>{children}</tbody>
          {footer}
        </table>
      </div>
    )
  }
)

/**
 * Render Our Example
 **/
render(
  <VirtualTable
    height={300}
    width="100%"
    itemCount={1000}
    itemSize={36}
    header={
      <thead>
        <tr>
          <th>Index</th>
          <th>Header 2</th>
          <th>Header 3</th>
          <th>Header 4</th>
        </tr>
      </thead>
    }
    row={Row}
    footer={
      <tfoot>
        <tr>
          <td>Footer 1</td>
          <td>Footer 2</td>
          <td>Footer 3</td>
          <td>Footer 4</td>
        </tr>
      </tfoot>
    }
  />,
  document.querySelector('main')
)

Terima kasih untuk ini, apakah ada yang mencoba (dengan sukses) untuk menggunakan ini dengan komponen InfiniteLoader ? ... Saya sudah mencoba menendangnya tetapi saya mengalami masalah dengan "pembungkus" bagian dalam, yang saya asumsikan karena infinite loader meneruskan props yang tidak terduga ke innerElementType.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat