React-window: HTML ν…Œμ΄λΈ” μš”μ†Œ μ‚¬μš©

에 λ§Œλ“  2018λ…„ 09μ›” 21일  Β·  34μ½”λ©˜νŠΈ  Β·  좜처: bvaughn/react-window

이것을 ν…Œμ΄λΈ”κ³Ό ν•¨κ»˜ μ‚¬μš©ν•˜λŠ” μ˜ˆκ°€ μžˆμŠ΅λ‹ˆκΉŒ? λ‚˜λŠ” 그것이 μž‘λ™ν•˜λ„λ‘ λ…Έλ ₯ν•˜κ³  μžˆμ§€λ§Œ 그것이 μž‘λ™ν•˜μ§€ μ•Šκ±°λ‚˜ λ‚΄κ°€ λ­”κ°€λ₯Ό 맀우 잘λͺ»ν•˜κ³  μžˆλ‹€λŠ” κ°•ν•œ μ˜μ‹¬μ„ 가지고 μžˆμŠ΅λ‹ˆλ‹€.
outerTagName을 "table"둜 μ„€μ •ν•˜κ³  innerTagName을 "tbody"둜 μ„€μ •ν–ˆμ§€λ§Œ 슀크둀이 λ°œμƒν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λ‹€μŒμ€ λ„μ›€μ΄λ˜λŠ”μ§€ ν™•μ‹€ν•˜μ§€ μ•Šμ€ λ‚΄ μ½”λ“œμž…λ‹ˆλ‹€ (ν•­λͺ©μ€ 개체 λͺ©λ‘μž…λ‹ˆλ‹€).

 <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

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

@pupudu μ €λŠ” μ—¬λŸ¬λΆ„μ˜ μ˜€ν”ˆ μ†ŒμŠ€ λ…Έλ ₯에 λ°•μˆ˜λ₯Ό

μ•„μ£Ό μž‘μ€ μ½”λ“œμ™€ λ§Žμ€ 창의λ ₯으둜 이것을 ν•΄λ‚Ό μˆ˜μžˆμ—ˆμŠ΅λ‹ˆλ‹€. μ½”λ“œλŠ” λˆ„κ΅¬λ‚˜ 볡사 / λΆ™μ—¬ λ„£κΈ° 및 μ›ν•˜λŠ”λŒ€λ‘œ ν™•μž₯ ν•  μˆ˜μžˆμ„λ§ŒνΌ κ°„λ‹¨ν•©λ‹ˆλ‹€. @bvaughn 방법 을 μ•Œμ•„ λ‚Έ ν›„ μ›ν•˜λŠ” 경우 λΌμ΄λΈŒλŸ¬λ¦¬μ— μΆ”κ°€ν•˜λŠ” 것은 맀우 μ‚¬μ†Œν•˜μ§€λ§Œ 방법을 μ•Œκ³  μžˆλ‹€λ©΄ μž¬μ •μ˜ν•˜λŠ” 것도 맀우 μ‚¬μ†Œν•©λ‹ˆλ‹€.

κ·Έκ²ƒμ˜ λΆ€μ‘± :

  • λ Œλ”λ§ ν›„ 첫 번째 ν–‰μ˜ "상단"μŠ€νƒ€μΌ 캑처
  • κ·Έ 값을 React.Context에 μ €μž₯ν•˜μ—¬ 전달할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • ν–‰ 자체 λŒ€μ‹  μ΄λ™λ˜λŠ” ν…Œμ΄λΈ” ꡬ성 μš”μ†Œμ— 값을 μ μš©ν•˜μ‹­μ‹œμ˜€.
  • 머리글 및 λ°”λ‹₯ κΈ€κ³Ό 같은 ν•­λͺ©μ— λŒ€ν•œ μΆ”κ°€ μŠ¬λ‘―μ„ μΆ”κ°€ν•˜μ‹­μ‹œμ˜€.
  • 라이브러리의 인체 곡학은 사물이 κΉ”λ”ν•˜κ²Œ μ „λ‹¬λ˜λŠ” 것을 ν—ˆμš©ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ React.ContextλŠ” ꡐ차 ꡬ성 μš”μ†Œ 톡신을 κ·Ήλ³΅ν•˜λŠ” μ˜μ›…μž…λ‹ˆλ‹€.

μž‘μ—… μ½”λ“œ μƒŒλ“œ λ°•μŠ€ : https://codesandbox.io/s/react-window-with-table-elements-d861o

μ°Έμ‘° 용 μ½”λ“œ

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')
)

λͺ¨λ“  34 λŒ“κΈ€

λ‚˜λŠ” 이것이 μ‹€μ œλ‘œ μž‘λ™ν•˜μ§€ μ•Šμ„ 것이라고 μƒκ°ν•©λ‹ˆλ‹€. λ‚΄κ°€ μ•„λŠ” ν•œ, HTMLTableElement λŠ” μœˆλ„μš° ꡬ성 μš”μ†Œμ— ν•„μš”ν•œ λ°©μ‹μœΌλ‘œ μ˜€λ²„ν”Œλ‘œλ₯Ό μ§€μ›ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μŠ€νƒ€μΌμ„ display: block _ λ³€κ²½ν•  수 μžˆμ§€λ§Œ _ μ—¬μ „νžˆ μ œλŒ€λ‘œ μž‘λ™ν•˜μ§€ μ•Šμ„ 것 κ°™μŠ΅λ‹ˆλ‹€. ( 여기에 μ˜ˆκ°€ μžˆμŠ΅λ‹ˆλ‹€.)

μ™œ ν…Œμ΄λΈ”μ΄ ν•„μš”ν•œκ°€μš”? 인라인 λΈ”λ‘μ΄λ‚˜ ν”Œλ ‰μŠ€ λ ˆμ΄μ•„μ›ƒμœΌλ‘œ λ™μΌν•œ μ—΄ λ ˆμ΄μ•„μ›ƒμ„ 얻을 수 μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

λͺ‡ 가지 μΆ”κ°€ 사항 :

  • width μ—μ„œ List κΉŒμ§€ ν•„μˆ˜ 맀개 λ³€μˆ˜λ₯Ό μ§€μ •ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.
  • key λ₯Ό 행에 μΆ”κ°€ ν•  ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.
  • itemSize λŠ” 30 κ°€ μ•„λ‹Œ () => 30 (쑰금 더 λ‚˜μ€ μ„±λŠ₯을 발휘 함).

λΉ λ₯Έ λ‹΅λ³€ κ°μ‚¬ν•©λ‹ˆλ‹€.
μš°λ¦¬λŠ” 이미 그것을 div둜 재 μž‘μ„±ν•˜λŠ” 것에 λŒ€ν•΄ λ…Όμ˜ν–ˆμ§€λ§Œ 이것은 기쑴의 λ‹€μ†Œ 큰 ꡬ성 μš”μ†Œλ₯Όμœ„ν•œ κ²ƒμ΄λ―€λ‘œ 재 μž‘μ„±μ„ μ‹œμž‘ν•˜κΈ° 전에 ν™•μΈν•˜κ³  μ‹Άμ—ˆμŠ΅λ‹ˆλ‹€. rc-table에 λŒ€ν•œ λ‹€λ₯Έ μ˜κ²¬μ„ λ³΄μ•˜μœΌλ―€λ‘œ μž‘λ™ν•΄μ•Όν•œλ‹€κ³  μƒκ°ν–ˆμŠ΅λ‹ˆλ‹€.
μ–΄μ¨Œλ“ , 재 μž‘μ„±μ€ μ‹ κ²½ 쓰지 λ§ˆμ„Έμš”. κ·Έλ§Œν•œ κ°€μΉ˜κ°€ μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

행에 ν‚€κ°€μ—†λŠ” 킀에 λŒ€ν•œ React κ²½κ³ λ₯Ό λ°›μ•˜λŠ”λ°, μ΄λŠ” itemKeyλ₯Ό μ„€μ •ν•˜λŠ” 것을 κ³ λ €ν•  λ•Œ ν˜Όλž€ μŠ€λŸ¬μ› μœΌλ―€λ‘œ κ±°κΈ°μ—μ„œ 무슨 일이 μΌμ–΄λ‚˜λŠ”μ§€ 잘 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€.

감사

Einar

2018 λ…„ 9 μ›” 21 일 16:52에 Brian Vaughn [email protected] 은 λ‹€μŒκ³Ό 같이 μΌμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” 이것이 μ‹€μ œλ‘œ μž‘λ™ν•˜μ§€ μ•Šμ„ 것이라고 μƒκ°ν•©λ‹ˆλ‹€. λ‚΄κ°€ μ•„λŠ” ν•œ HTMLTableElementλŠ” μœˆλ„μš° ꡬ성 μš”μ†Œμ— ν•„μš”ν•œ λ°©μ‹μœΌλ‘œ μ˜€λ²„ν”Œλ‘œλ₯Ό μ‹€μ œλ‘œ μ§€μ›ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. display : block μŠ€νƒ€μΌμ„ λ³€κ²½ν•  수 μžˆμ§€λ§Œ μ—¬μ „νžˆ μ œλŒ€λ‘œ μž‘λ™ν•˜μ§€ μ•Šμ„ 것이라고 μƒκ°ν•©λ‹ˆλ‹€.

μ™œ ν…Œμ΄λΈ”μ΄ ν•„μš”ν•œκ°€μš”? 인라인 λΈ”λ‘μ΄λ‚˜ ν”Œλ ‰μŠ€ λ ˆμ΄μ•„μ›ƒμœΌλ‘œ λ™μΌν•œ μ—΄ λ ˆμ΄μ•„μ›ƒμ„ 얻을 수 μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

λͺ‡ 가지 μΆ”κ°€ 사항 :

List에 ν•„μš”ν•œ 맀개 λ³€μˆ˜ λ„ˆλΉ„λ₯Ό μ§€μ •ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.
행에 ν‚€λ₯Ό μΆ”κ°€ ν•  ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.
itemSizeλŠ” () => 30이 μ•„λ‹Œ 30 일 수 μžˆμŠ΅λ‹ˆλ‹€ (쑰금 더 잘 μˆ˜ν–‰λ¨).
β€”
μŠ€λ ˆλ“œλ₯Ό μž‘μ„±ν–ˆκΈ° λ•Œλ¬Έμ— μˆ˜μ‹  ν•œ κ²ƒμž…λ‹ˆλ‹€.
이 이메일에 직접 λ‹΅μž₯ν•˜κ±°λ‚˜ GitHubμ—μ„œ λ³΄κ±°λ‚˜ λŒ€ν™” λͺ©λ‘μ„ μŒμ†Œκ±°ν•˜μ„Έμš”.

행에 ν‚€κ°€μ—†λŠ” 킀에 λŒ€ν•œ React κ²½κ³ λ₯Ό λ°›μ•˜λŠ”λ°, μ΄λŠ” itemKeyλ₯Ό μ„€μ •ν•˜λŠ” 것을 κ³ λ €ν•  λ•Œ ν˜Όλž€ μŠ€λŸ¬μ› μœΌλ―€λ‘œ κ±°κΈ°μ—μ„œ 무슨 일이 μΌμ–΄λ‚˜λŠ”μ§€ 잘 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€.

이것은 μ˜ˆμƒλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. (Code Sandboxλ₯Ό 톡해) μž¬ν˜„ 사둀λ₯Ό λ‚˜μ™€ 곡유 ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

였, μ£„μ†‘ν•©λ‹ˆλ‹€. itemKey ν•¨μˆ˜κ°€ 일뢀 ν•­λͺ©μ— λŒ€ν•΄ undefined λ₯Ό λ°˜ν™˜ ν•œ κ²½μš°μ—λ§Œ _ μ˜ˆμƒ 될 κ²ƒμž„μ„ μΆ”κ°€ν•΄μ•Όν•©λ‹ˆλ‹€.이 경우 ν•΄λ‹Ή ν•¨μˆ˜μ— λŒ€ν•œ μˆ˜μ •μ΄ ν•„μš”ν•©λ‹ˆλ‹€.

@bvaughn λ‚˜λŠ” μ˜€λ²„ν”Œλ‘œ 지원이 μ œν•œ μš”μ†Œ 인 것에 λŒ€ν•΄ ꡬ체적으둜 찾지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€. ν₯λ―Έλ‘­κ²Œλ„ 그게 뭔지 μ•Œκ³  μ‹ΆμŠ΅λ‹ˆλ‹€. 두 가지 λͺ¨λ‘μ— λŒ€ν•œ 핡심 κΈ°λŠ₯을 μ§€μ›ν•˜λŠ” 것이 지루할 수 μžˆλ‹€λŠ” 것을 ν™•μ‹€νžˆ μ•Œκ³  μžˆμ§€λ§Œ, κΈ°λ³Έ λͺ©λ‘ μš”μ†Œκ°€ ν˜„μž¬ κ΅¬ν˜„ 자의 μ„ νƒμ—μ„œ λ²—μ–΄λ‚œ λͺ¨λ“  것 κ°™μŠ΅λ‹ˆλ‹€. λ‚˜ μžμ‹ κ³Ό κ³ μ • 헀더 μ‹œλ‚˜λ¦¬μ˜€μ™€ ν•¨κ»˜ λ°˜μ‘ 창을 μ‚¬μš©ν•˜λŠ” λͺ¨λ“  μ‚¬λžŒμ„ μœ„ν•΄ λ§ν•˜λ©΄ ν…Œμ΄λΈ” λ ˆμ΄μ•„μ›ƒμ— λ‚΄μž₯ 된 고유 ν•œ ν…Œμ΄λΈ” ν˜•μ‹ 지원을 μ–»λŠ” 것이 쒋을 κ²ƒμž…λ‹ˆλ‹€. display : table을 μ‚¬μš©ν•˜λ©΄ "일뢀"개발 μ˜€λ²„ ν—€λ“œκ°€ λ°œμƒν•˜λ©° μš°μ—°νžˆ ν…Œμ΄λΈ”μ„ μ‚¬μš©ν•˜μ—¬ λΉŒλ“œ 될 μˆ˜μžˆλŠ” μ£Όλ³€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„μœ„ν•œ μΌνšŒμ„± λ ˆμ΄μ•„μ›ƒμž…λ‹ˆλ‹€. λ‚˜λŠ” 항상 cssλ₯Ό 톡해 μ˜€λ²„ν”Œλ‘œ λ˜λŠ” 기타 속성을 μ‘°μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€ (μ–΄μ¨Œλ“  ν˜„μž¬ κ΅¬ν˜„μ—μ„œ μˆ˜ν–‰ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€). elementType μ†Œν’ˆμ΄ λ¬Έμ œκ°€λ˜μ§€ μ•ŠμŠ΅λ‹ˆκΉŒ?

@bvaughn λ‚˜λŠ” μ˜€λ²„ν”Œλ‘œ 지원이 μ œν•œ μš”μ†Œ 인 것에 λŒ€ν•΄ ꡬ체적으둜 찾지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.

λ‚΄κ°€ 졜고의 문ꡬλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ•˜μ„ μˆ˜λ„ μžˆμ§€λ§Œ λ‚΄κ°€ μ—°κ²° ν•œ μƒŒλ“œ λ°•μŠ€ ( rrn61wkzwm )λ₯Ό 보면 μ˜ˆμƒμΉ˜ λͺ»ν•œ λ™μž‘μ„ 보게 될 κ²ƒμž…λ‹ˆλ‹€.

λ‹€μŒμ€ HTML 인 또 λ‹€λ₯Έ μ˜ˆμž…λ‹ˆλ‹€. lx65871p69

HTMLSelectElement ( <tbody> )λŠ” height 및 overflow 와 같은 μŠ€νƒ€μΌμ„ λ¬΄μ‹œν•˜λ―€λ‘œ 창에 μ“Έλͺ¨κ°€ μ—†μŠ΅λ‹ˆλ‹€. ν‘œμ‹œ λͺ¨λ“œ ( display: block )λ₯Ό λ³€κ²½ν•˜μ—¬μ΄ 문제λ₯Ό "μˆ˜μ •"ν•  수 μžˆμ§€λ§Œ HTMLTableElement μ‚¬μš© λͺ©μ μ€ μ—΄ 크기 μ‘°μ • λ™μž‘μ„ μ†μƒμ‹œν‚€κΈ° λ•Œλ¬Έμ— λ¬΄νš¨ν™”λ©λ‹ˆλ‹€.

이 μ—΄ 크기 μ‘°μ • λ™μž‘μ€ 크기가 μ—΄μ˜ λ‚΄μš©μ— 따라 λ‹€λ₯΄κΈ° λ•Œλ¬Έμ— (μ‚¬μš©μžκ°€ 슀크둀 ν•  λ•Œ 변경됨) μ°½ μ‚¬μš© μ‚¬λ‘€μ—μ„œ μ‹œμž‘ν•˜κΈ° μœ„ν•΄ κΉ¨μ‘ŒμŠ΅λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ 그것은 κΈ°λ³Έ λͺ©λ‘ μš”μ†Œκ°€ ν˜„μž¬ κ΅¬ν˜„ 자의 μ„ νƒμ—μ„œ λ²—μ–΄λ‚œ λͺ¨λ“  κ²ƒμ²˜λŸΌ λ³΄μž…λ‹ˆλ‹€ ... elementType prop이 λ¬Έμ œμž…λ‹ˆκΉŒ?

당신이 μ •λ§λ‘œ μ›ν•˜λŠ” 경우 νƒœκ·Έ μœ ν˜•μ„ 이미 지정할 수 μžˆμŠ΅λ‹ˆλ‹€ ( 2j0z718mwy ).

λ‚˜ μžμ‹ κ³Ό κ³ μ • 헀더 μ‹œλ‚˜λ¦¬μ˜€μ™€ ν•¨κ»˜ λ°˜μ‘ 창을 μ‚¬μš©ν•˜λŠ” λͺ¨λ“  μ‚¬λžŒμ„ μœ„ν•΄ λ§ν•˜λ©΄ ν…Œμ΄λΈ” λ ˆμ΄μ•„μ›ƒμ— λ‚΄μž₯ 된 고유 ν•œ ν…Œμ΄λΈ” ν˜•μ‹ 지원을 μ–»λŠ” 것이 쒋을 κ²ƒμž…λ‹ˆλ‹€.

HTMLTableElement μ‚¬μš©ν•˜λ©΄ μœ„μ—μ„œ μ„€λͺ…ν•œ 이유둜 λ¬Έμ œκ°€ 될 수 μžˆμŠ΅λ‹ˆλ‹€. κ³ μ • ν—€λ”κ°€μžˆλŠ” ν‘œ / κ·Έλ¦¬λ“œ λ ˆμ΄μ•„μ›ƒμ„ μ›ν•œλ‹€λ©΄ 일반 λͺ©λ‘ ꡬ성 μš”μ†Œ 쀑 ν•˜λ‚˜λ₯Ό μ‚¬μš©ν•˜μ—¬μ΄λ₯Ό μˆ˜ν–‰ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. pk78pvwnkx

μ™œ ν…Œμ΄λΈ”μ΄ ν•„μš”ν•œκ°€μš”? 인라인 λΈ”λ‘μ΄λ‚˜ ν”Œλ ‰μŠ€ λ ˆμ΄μ•„μ›ƒμœΌλ‘œ λ™μΌν•œ μ—΄ λ ˆμ΄μ•„μ›ƒμ„ 얻을 수 μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

일뢀 접근성을 μœ„ν•΄ ν…Œμ΄λΈ” ​​ꡬ쑰가 ν•„μš”ν•  수 μžˆμŠ΅λ‹ˆλ‹€ (예 : μ˜λ―Έμ—†λŠ” div에 λΉ„ν•΄ 더 λ‚˜μ€ ν™”λ©΄ 읽기)? λ‚˜λŠ” μ—¬κΈ°μ—μ„œ μΆ”μΈ‘ν•˜κ³ μžˆλ‹€.

이 경우 CSS ν‘œμ‹œ μŠ€νƒ€μΌκ³Ό ν…Œμ΄λΈ” μš”μ†Œμ— 고유 ν•œ λ‹€λ₯Έ μŠ€νƒ€μΌμ„ μž¬μ •μ˜ ν•  κ²ƒμž…λ‹ˆλ‹€.

μ•½ 9 λ…„ 전에 λ³΅μž‘ν•œ ν…Œμ΄λΈ” ꡬ성 μš”μ†Œ (상단 및 μ™Όμͺ½μ˜ κ³ μ • / κ³ μ • 머리글, λ³΅μž‘ν•œ colspan / rowspan ꡬ쑰 및 κ·Έ λ’€μ—μžˆλŠ” ꡬ쑰λ₯Ό μ„€λͺ…ν•˜λŠ” 데이터 λͺ¨λΈ 포함)λ₯Ό ꡬ좕 ν•œ κ²½ν—˜μ΄ μžˆμŠ΅λ‹ˆλ‹€. 가상화가 μ—†λ‹€λŠ” 것을 κΈ°μ–΅ν•˜λŠ” ν•œ)이 ꡬ성 μš”μ†Œλ₯Ό λ‹΄λ‹Ήν–ˆλ˜ λ™λ£Œκ°€ μ μ ˆν•œ ν…Œμ΄λΈ” μš”μ†Œμ—μ„œμ΄λ₯Ό κ΅¬ν˜„ν•˜λ €κ³  μ‹œλ„ν–ˆκ³  λ ˆμ΄μ•„μ›ƒμ΄ νŠΉμ • λ°©μ‹μœΌλ‘œ μž‘λ™ν•˜λ„λ‘ κ°•μ œν•˜λŠ” 데 어렀움을 κ²ͺ은 λ‹€μŒ μˆœμˆ˜ν•œ JavaScript둜 ν…Œμ΄λΈ” λ ˆμ΄μ•„μ›ƒμ„ κ΅¬ν˜„ν•˜κΈ°λ‘œ κ²°μ •ν–ˆμŠ΅λ‹ˆλ‹€. μ ˆλŒ€ μœ„μΉ˜ 및 크기가 μ§€μ •λœ div. 이 μ†”λ£¨μ…˜μ€ μ™„λ²½ν•˜κ²Œ μž‘λ™ν–ˆμŠ΅λ‹ˆλ‹€. μ΄μƒν•œ λ ˆμ΄μ•„μ›ƒ 점프, λΆ€λ“œλŸ¬μš΄ 슀크둀 (ν–‰ / μ—΄λ‹Ή μ•„λ‹˜) λ“±μž…λ‹ˆλ‹€.

일뢀 접근성을 μœ„ν•΄ ν…Œμ΄λΈ” ​​ꡬ쑰가 ν•„μš”ν•  수 μžˆμŠ΅λ‹ˆλ‹€ (예 : μ˜λ―Έμ—†λŠ” div에 λΉ„ν•΄ 더 λ‚˜μ€ ν™”λ©΄ 읽기)? λ‚˜λŠ” μ—¬κΈ°μ—μ„œ μΆ”μΈ‘ν•˜κ³ μžˆλ‹€.

Aria 역할을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€ πŸ˜„

μ² μ €νžˆ κ°μ‚¬ν•©λ‹ˆλ‹€. 당신은 단지 ν•˜λ‚˜μ˜ 문제λ₯Ό ν•΄κ²°ν•˜λŠ” ν”„λ‘œν†  νƒ€μž…μ„ μ‹œλ„ν•˜μ—¬ λ‹€λ₯Έ 문제λ₯Ό λ§Œλ“€μ–΄ λ‚΄κΈ° μœ„ν•΄ 토끼 ꡴둜 λ‚΄λ €κ°€λŠ” λ‚˜λ₯Ό κ΅¬ν–ˆμŠ΅λ‹ˆλ‹€.

μ•ˆλ…•ν•˜μ„Έμš”
μƒˆ μŠ€λ ˆλ“œλ₯Ό λ§Œλ“œλŠ” λŒ€μ‹  κΈ°μ‘΄ μŠ€λ ˆλ“œλ₯Ό μ°ΎμœΌλ €κ³ ν–ˆμŠ΅λ‹ˆλ‹€. 쒋은 곳에 μžˆμ—ˆμœΌλ©΄ μ’‹κ² μ–΄μš” ...

FixedSizeGrid λŒ€ν•΄ 두 개의 셀을 λ³‘ν•©ν•˜κΈ° μœ„ν•΄ μΌμ’…μ˜ "colspan"을 μ‚¬μš©ν•˜λŠ” 방법이 μžˆμŠ΅λ‹ˆκΉŒ?
이 μ§ˆλ¬Έμ€ μ—¬κΈ° μ—μ„œ μ‹œμž‘λœ 또 λ‹€λ₯Έ 토둠에 μ˜μ‘΄ν•˜μ§€λ§Œ 더 μ΄ν•΄ν•˜κΈ° μœ„ν•΄ 여기에 κ²Œμ‹œν•˜λŠ” 것을 μ„ ν˜Έν•©λ‹ˆλ‹€.

FixedSizeGrid에 λŒ€ν•΄ 두 개의 셀을 λ³‘ν•©ν•˜κΈ° μœ„ν•΄ μΌμ’…μ˜ "colspan"을 μ‚¬μš©ν•˜λŠ” 방법이 μžˆμŠ΅λ‹ˆκΉŒ?

μ•„λ‹ˆμš”. μ§€μ›λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

@einarq @BlaineBradbury @sompylasar μ—¬μ „νžˆ 관심이 https://window-table.netlify.com/ μ—μ„œ 라이브 데λͺ¨λ₯Ό λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

λ‚΄κ°€ ν…Œμ΄λΈ” νƒœκ·Έλ₯Ό

λ‚˜λŠ” λΈŒλΌμ΄μ–Έμ—κ²Œμ΄ κ΅¬ν˜„μ— λŒ€ν•΄ μ–΄λ–»κ²Œ μƒκ°ν•˜λŠ”μ§€ νƒœκ·Έλ₯Ό 달고 물어보고 μ‹Άμ—ˆλ‹€ (κ·ΈλŠ” html ν…Œμ΄λΈ” νƒœκ·Έκ°€ μž‘λ™ν•˜μ§€ μ•ŠλŠ”λ‹€κ³  μ–ΈκΈ‰ν–ˆκΈ° λ•Œλ¬Έμ—). κ·ΈλŸ¬λ‚˜ κ·ΈλŠ” 이미 λ‚˜λ₯Ό μΆ©λΆ„νžˆ λ„μ™”μŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ μ—¬λŸ¬λΆ„λ“€μ—κ²Œ λ§‘κΈ°κ² μŠ΅λ‹ˆλ‹€.

κ°μ‚¬ν•©λ‹ˆλ‹€.

@pupuduλŠ” ν₯미둜운 μ ‘κ·Ό λ°©μ‹μž…λ‹ˆλ‹€. 헀더와 행에 λŒ€ν•΄ λ³„λ„μ˜ <table> νƒœκ·Έλ₯Ό κ°–λŠ” 것에 λŒ€ν•œ μ ‘κ·Όμ„± λ¬Έμ œκ°€ μžˆλŠ”μ§€ λͺ¨λ₯΄κ² μ§€λ§Œ 그렇지 μ•ŠμœΌλ©΄ κΉ”λ”ν•œ μ•„μ΄λ””μ–΄μž…λ‹ˆλ‹€.

react-datasheet 와 ν•¨κ»˜ react-window react-datasheet 을 μ‚¬μš©ν•˜λ €κ³ ν•˜λŠ”λ° 기본적으둜 μž‘λ™ν•©λ‹ˆλ‹€.

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>,
      };
    }),
  );
}

λ Œλ”λ§, μœ μΌν•œ λ¬Έμ œλŠ” Warning: validateDOMNesting(...): <tr> cannot appear as a child of <div>. index.js:1437 Warning: validateDOMNesting(...): <div> cannot appear as a child of <tbody>.

이봐, λ‚˜λŠ” React-Table둜 이것을 μ‹œλ„ν•˜κ³  있으며 ν…Œμ΄λΈ” μš”μ†Œ λŒ€μ‹  divλ₯Ό μ‚¬μš©ν•΄μ•Όν•œλ‹€λŠ” 것을 μ•Œμ•˜μŠ΅λ‹ˆλ‹€. μ΄κ²ƒμ˜ λ¬Έμ œλŠ” 재질 / λΆ€νŠΈ 슀트랩과 같은 μŠ€νƒ€μΌλ§ λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ΄λŸ¬ν•œ μš”μ†Œμ— μ˜μ‘΄ν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. λ”°λΌμ„œ λ‚΄ ν…Œμ΄λΈ” μŠ€ν‚€λ§ˆλ₯Ό ν…Œμ΄λΈ” μš”μ†Œ λŒ€μ‹  div둜 λ³€κ²½ν•˜λŠ” 것이 훨씬 더 λ§Žμ€ μž‘μ—…μž…λ‹ˆλ‹€. ν‘œ μš”μ†Œλ₯Ό μ‚¬μš©ν•˜μ—¬ λΉ„κ΅ν•˜λŠ” 것이 κ°€λŠ₯ν•©λ‹ˆκΉŒ μ•„λ‹ˆλ©΄ μ§€κΈˆ λ‚˜λ§Œμ˜ μŠ€νƒ€μΌμ„ λ§Œλ“€μ–΄μ•Όν•©λ‹ˆκΉŒ?

@simkessy 이미 눈치 채지
https://window-table.netlify.com/

@pupudu μ €λŠ” μ—¬λŸ¬λΆ„μ˜ μ˜€ν”ˆ μ†ŒμŠ€ λ…Έλ ₯에 λ°•μˆ˜λ₯Ό

μ•„μ£Ό μž‘μ€ μ½”λ“œμ™€ λ§Žμ€ 창의λ ₯으둜 이것을 ν•΄λ‚Ό μˆ˜μžˆμ—ˆμŠ΅λ‹ˆλ‹€. μ½”λ“œλŠ” λˆ„κ΅¬λ‚˜ 볡사 / λΆ™μ—¬ λ„£κΈ° 및 μ›ν•˜λŠ”λŒ€λ‘œ ν™•μž₯ ν•  μˆ˜μžˆμ„λ§ŒνΌ κ°„λ‹¨ν•©λ‹ˆλ‹€. @bvaughn 방법 을 μ•Œμ•„ λ‚Έ ν›„ μ›ν•˜λŠ” 경우 λΌμ΄λΈŒλŸ¬λ¦¬μ— μΆ”κ°€ν•˜λŠ” 것은 맀우 μ‚¬μ†Œν•˜μ§€λ§Œ 방법을 μ•Œκ³  μžˆλ‹€λ©΄ μž¬μ •μ˜ν•˜λŠ” 것도 맀우 μ‚¬μ†Œν•©λ‹ˆλ‹€.

κ·Έκ²ƒμ˜ λΆ€μ‘± :

  • λ Œλ”λ§ ν›„ 첫 번째 ν–‰μ˜ "상단"μŠ€νƒ€μΌ 캑처
  • κ·Έ 값을 React.Context에 μ €μž₯ν•˜μ—¬ 전달할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • ν–‰ 자체 λŒ€μ‹  μ΄λ™λ˜λŠ” ν…Œμ΄λΈ” ꡬ성 μš”μ†Œμ— 값을 μ μš©ν•˜μ‹­μ‹œμ˜€.
  • 머리글 및 λ°”λ‹₯ κΈ€κ³Ό 같은 ν•­λͺ©μ— λŒ€ν•œ μΆ”κ°€ μŠ¬λ‘―μ„ μΆ”κ°€ν•˜μ‹­μ‹œμ˜€.
  • 라이브러리의 인체 곡학은 사물이 κΉ”λ”ν•˜κ²Œ μ „λ‹¬λ˜λŠ” 것을 ν—ˆμš©ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ React.ContextλŠ” ꡐ차 ꡬ성 μš”μ†Œ 톡신을 κ·Ήλ³΅ν•˜λŠ” μ˜μ›…μž…λ‹ˆλ‹€.

μž‘μ—… μ½”λ“œ μƒŒλ“œ λ°•μŠ€ : https://codesandbox.io/s/react-window-with-table-elements-d861o

μ°Έμ‘° 용 μ½”λ“œ

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 μ ‘κ·Ό 방식을 μ’‹μ•„ν•©λ‹ˆλ‹€. 이λ₯Ό λ‹¬μ„±ν•˜κΈ° μœ„ν•΄ Contextλ₯Ό μ‚¬μš©ν•˜λŠ” 정말 ν₯미둜운 μ•„μ΄λ””μ–΄μž…λ‹ˆλ‹€. 두 개, ν•˜λ‚˜λŠ” 헀더 용, λ‹€λ₯Έ ν•˜λ‚˜λŠ” λ³Έλ¬Έ 용으둜 λ Œλ”λ§ν•˜λŠ” 방식과 달리 ν•˜λ‚˜μ˜ ν…Œμ΄λΈ” 만 λ Œλ”λ§ν•œλ‹€λŠ” 사싀이 λ§ˆμŒμ— λ“­λ‹ˆλ‹€. 이둜 인해 μ°½ ν…Œμ΄λΈ” μ‚¬μš©μžμ—κ²Œ λ§Žμ€ ν˜Όλž€μ΄ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.

λ§ˆμŒμ— 듀지 μ•ŠμœΌμ‹œλ©΄μ΄ 아이디어λ₯Ό μ°½κ°€ ν…Œμ΄λΈ”μ—μ„œ μ‚¬μš©ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€. κ°€μž₯ 큰 도전은 μ½˜ν…μΈ λ₯Ό 기반으둜 ν–‰μ˜ 크기λ₯Ό μžλ™μœΌλ‘œ μ‘°μ •ν•˜λŠ” 방법을 μ°ΎλŠ” κ²ƒμž…λ‹ˆλ‹€ (적어도 windo-table의 κ°€μž₯ 큰 λ„μ „μ΄μ—ˆμŠ΅λ‹ˆλ‹€).

@jamesmfriedman 맀우 유망 ν•΄ λ³΄μž…λ‹ˆλ‹€. @bvaughn 이 μ ‘κ·Ό 방식에 λŒ€ν•΄ 우렀 사항이 μžˆμŠ΅λ‹ˆκΉŒ?

@jamesmfriedman 헀더가 μ½˜ν…μΈ μ™€ ν•¨κ»˜ μœ„λ‘œ μŠ€ν¬λ‘€λ˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. λˆμ ν•˜κ²Œ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆκΉŒ?

μ‹€μ œλ‘œ κ°€λŠ₯ν•˜λ©°μ΄ κ΅¬ν˜„μ—λ§Œ κ΅­ν•œλ˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€. HTML ν…Œμ΄λΈ” μš”μ†Œλ₯Ό μ‚¬μš©ν•˜μ—¬ κ³ μ • 헀더λ₯Ό κ²€μƒ‰ν•˜κΈ° λ§Œν•˜λ©΄λ©λ‹ˆλ‹€. 이 μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 방법은 μ‹€μ œλ‘œ TH μš”μ†Œ μœ„μΉ˜λ₯Ό κ³ μ •ν•˜λŠ” κ²ƒμž„μ„ λ§‰μ—°ν•˜κ²Œ κΈ°μ–΅ν•©λ‹ˆλ‹€.

@jamesmfriedman 예λ₯Ό λ“€μ–΄ μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€ @marink 여기에 κ³ μ • 헀더에 λŒ€ν•œ μ˜ˆκ°€ μžˆμŠ΅λ‹ˆλ‹€ https://codesandbox.io/s/react-window-with-table-elements-jj70e style={{ position: 'sticky', top: 0 }}> 을 μΆ”κ°€ν•΄μ•Όν•©λ‹ˆλ‹€ th νƒœκ·Έ

@jamesmfriedman 예λ₯Ό λ“€μ–΄ μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€. λ‚˜λŠ” 그것을 μ‚¬μš©ν•˜λŠ” 것을 쑰사 ν•  것이닀. ν•˜μ§€λ§Œ top : 0 κ³Ό position stickyλ₯Ό μ‚¬μš©ν•˜λŠ” λŒ€μ‹  top을 λ‹€μ‹œ κ³„μ‚°ν•˜κ³  ν…Œμ΄λΈ” μš”μ†Œμ— μ ˆλŒ€ μœ„μΉ˜λ₯Ό κ°–λŠ” 것이 갈 길이라고 μƒκ°ν•©λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ 당신이 μœ„μΉ˜λ₯Ό κ³ μ •ν•˜μ—¬ th μš”μ†Œμ— κ³ μ • 헀더λ₯Ό κ°€μ Έ 였면 λͺ¨λ“  것이 λΉ λ₯Έ μŠ€ν¬λ‘€μ—μ„œ μ—‰λ§μ΄λ˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

λ”°λΌμ„œ 79 행은 <table style={{ top: 0, position: 'sticky', width: '100%' }}>

λ˜ν•œ μ•„λž˜μͺ½μ—μžˆμ„ λ•Œ 계속 μŠ€ν¬λ‘€ν•˜λŠ” 경우 슀크둀 λ¬Έμ œκ°€ ν•΄κ²°λ©λ‹ˆλ‹€.

HTML ν…Œμ΄λΈ”μ„ μ‚¬μš©ν•˜λŠ” 또 λ‹€λ₯Έ 쒋은 μ΄μœ λŠ” IE11을 μ§€μ›ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. FixedSizeList ν•˜κ³  CSS-grid둜 μŠ€νƒ€μΌμ„ μ§€μ •ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λ°˜μ‘ ν˜• μ—΄, 크기가 λ‹€λ₯Έ μ—΄ λ“±κ³Ό 같은 λ‹€λ₯Έ κΈ°λŠ₯을 μΆ”κ°€ν•˜κ³  λͺ¨λ‘ IE11κ³Ό ν•¨κ»˜ μž‘λ™ν•˜λ„λ‘ν•΄μ•Όν•˜λŠ” 경우 μ—„μ²­λ‚œ μ–‘μ˜ μ½”λ“œκ°€ μƒμ„±λ©λ‹ˆλ‹€. HTML ν…Œμ΄λΈ”μ€ 기본적으둜 μ½”λ“œμ—†μ΄ μž‘λ™ν•©λ‹ˆλ‹€.

IE11은 더 이상 μ§€μ›ν•΄μ•Όν•˜λŠ” 것이 μ•„λ‹™λ‹ˆλ‹€. :)

λͺ¨λ“  FE κ°œλ°œμžλŠ” IE11에 μ£½μŒμ„ μ›ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ•ˆνƒ€κΉκ²Œλ„ μš°λ¦¬κ°€ 상상쑰차 ν•  μˆ˜μ—†λŠ” 이유둜 움직일 μˆ˜μ—†λŠ” νšŒμ‚¬ / μ‚¬λžŒλ“€μ΄ μžˆμŠ΅λ‹ˆλ‹€. λ°”λΌκ±΄λŒ€, μ•žμœΌλ‘œ λͺ‡ λ…„ 밖에 걸리지 μ•Šμ•˜ μœΌλ©΄ν•©λ‹ˆλ‹€. κ·Έ μ „κΉŒμ§€λŠ” μ›ν•˜λ“  μ›ν•˜μ§€ μ•Šλ“  IE11을 μ§€μ›ν•΄μ•Όν•©λ‹ˆλ‹€.

λ‚˜μ—κ²Œλ„ μ‚Όν‚€κΈ° νž˜λ“  μ•½μ΄μ—ˆλ‹€.

@ olafur164 λΉ λ₯Έ μŠ€ν¬λ‘€μ—μ„œ 깨지지 μ•ŠλŠ” λˆμ ν•œ 헀더에 λŒ€ν•œ μˆ˜μ •μ— κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€. λ§€λ„λŸ½κ²Œν•˜λŠ” κ²ƒκ³ΌλŠ” λ°˜λŒ€λ‘œ ν•œ λ²ˆμ— ν•œ ν–‰μ”© μŠ€ν¬λ‘€ν•˜λ―€λ‘œ "κ³ μ • 된"λͺ¨μ–‘을 μœ μ§€ν•˜λŠ” 방법이 μžˆλŠ”μ§€ μ•Œκ³  μžˆμŠ΅λ‹ˆκΉŒ?

react-virtualized ( react-window 문제 νŽ˜μ΄μ§€ 일지라도)와 λ™μΌν•œ λ¬Έμ œκ°€ λ‚˜νƒ€λ‚˜λŠ” material-table (가상화와 κ²°ν•© ν…Œμ΄λΈ” μš”μ†Œ)μ΄λΌλŠ” https://github.com/mbrn/ material-table / issues / 891 # issuecomment -681986647. μŠ€νƒ€μΌλ§ 문제 및 validateDOMNesting(...) 경고와 같은 λͺ‡ 가지 λ¬Έμ œκ°€ μ—¬μ „νžˆ μžˆμŠ΅λ‹ˆλ‹€.

@jamesmfriedman 예λ₯Ό λ“€μ–΄ μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€ @marink 여기에 κ³ μ • ν—€λ”μ˜ μ˜ˆκ°€ μžˆμŠ΅λ‹ˆλ‹€. th νƒœκ·Έμ— style={{ position: 'sticky', top: 0 }}> 을 μΆ”κ°€ν•΄μ•Όν•©λ‹ˆλ‹€.

μ•ˆλ…•ν•˜μ„Έμš” @JCofman , CSS μˆ˜μ •μ„ μ‹œλ„ν–ˆμ§€λ§Œ μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 여기에 μ½”λ“œ μƒŒλ“œ λ°•μŠ€μ˜ μ˜ˆμž…λ‹ˆλ‹€ - https://codesandbox.io/s/react-window-with-table-elements-forked-huti6?file=/src/index.tsx은 : 514-542

두 가지 λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

  1. μ œμžλ¦¬μ— μŠ€νƒ€μΌμ΄ μžˆμŒμ—λ„ λΆˆκ΅¬ν•˜κ³  헀더가 상단에 κ³ μ •λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  2. μœ„μͺ½ λ°©ν–₯으둜 크게 μŠ€ν¬λ‘€ν•˜λŠ” λ™μ•ˆ 헀더가 κΉœλ°•μ΄κ±°λ‚˜ κΉœλ°•μž…λ‹ˆλ‹€.
    [μž¬ν˜„ 단계-50 % μ•„λž˜λ‘œ 슀크둀 ν•œ λ‹€μŒ λΉ λ₯΄κ²Œ μœ„λ‘œ μŠ€ν¬λ‘€ν•˜κ³  헀더 이동을 κ΄€μ°°ν•©λ‹ˆλ‹€.].

미리 κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€ :)

@jamesmfriedman μ ‘κ·Ό 방식을 μ’‹μ•„ν•©λ‹ˆλ‹€. 이λ₯Ό λ‹¬μ„±ν•˜κΈ° μœ„ν•΄ Contextλ₯Ό μ‚¬μš©ν•˜λŠ” 정말 ν₯미둜운 μ•„μ΄λ””μ–΄μž…λ‹ˆλ‹€. 두 개, ν•˜λ‚˜λŠ” 헀더 용, λ‹€λ₯Έ ν•˜λ‚˜λŠ” λ³Έλ¬Έ 용으둜 λ Œλ”λ§ν•˜λŠ” 방식과 달리 ν•˜λ‚˜μ˜ ν…Œμ΄λΈ” 만 λ Œλ”λ§ν•œλ‹€λŠ” 사싀이 λ§ˆμŒμ— λ“­λ‹ˆλ‹€. 이둜 인해 μ°½ ν…Œμ΄λΈ” μ‚¬μš©μžμ—κ²Œ λ§Žμ€ ν˜Όλž€μ΄ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.

λ§ˆμŒμ— 듀지 μ•ŠμœΌμ‹œλ©΄μ΄ 아이디어λ₯Ό μ°½κ°€ ν…Œμ΄λΈ”μ—μ„œ μ‚¬μš©ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€. κ°€μž₯ 큰 도전은 μ½˜ν…μΈ λ₯Ό 기반으둜 ν–‰μ˜ 크기λ₯Ό μžλ™μœΌλ‘œ μ‘°μ •ν•˜λŠ” 방법을 μ°ΎλŠ” κ²ƒμž…λ‹ˆλ‹€ (적어도 windo-table의 κ°€μž₯ 큰 λ„μ „μ΄μ—ˆμŠ΅λ‹ˆλ‹€).

λ‚΄κ°€ μ‚¬μš©ν•˜κ³  있기 λ•Œλ¬Έμ— 맀우 λΉ„μŠ·ν•œ 해결책을 μ°ΎκΈ° κ²°κ΅­ display: grid 가진 display: contents 행에 λŒ€ν•œμ˜ μ œμ•½μ— μ΄λ ‡κ²Œ 기본적으둜,이 뢀착을 table > tr μš”μ†Œ.

context + refsλ₯Ό μ‚¬μš©ν•˜μ—¬ λ‚΄λΆ€ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν–ˆμ§€λ§Œ 첫 번째 μžμ‹μ˜ style.top 값을 μ‘°νšŒν•˜μ—¬ λ™μΌν•œ μž‘μ—…μ„ μˆ˜ν–‰ ν•  수 μžˆμœΌλ―€λ‘œ μ™„μ „νžˆ λΆˆν•„μš”ν•©λ‹ˆλ‹€.

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>
    )
  }
)

μŠ€νƒ€μΌ μ†Œν’ˆμ€ 각 행에 λŒ€ν•΄ createElementλ₯Ό μˆ˜ν–‰ ν•  λ•Œ λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ μ œκ³΅ν•˜κ³  νŠΉμ • Row ꡬ성 μš”μ†Œκ°€ style 을 tr ν• λ‹Ήν•˜μ§€ μ•ŠμœΌλ―€λ‘œ κ·Έλ“€ 쀑 ν•˜λ‚˜λ₯Ό μ „λ‹¬ν•©λ‹ˆλ‹€.

μ΅œκ·Όμ— 이런 게 ꢁ금 ν–ˆμ–΄μš”. css μ‚¬μš©μž μ •μ˜ 속성을 톡해 μ˜μ‚¬ μš”μ†Œ (이후 / 이전)λ₯Ό μ‚¬μš©ν•˜μ—¬ νŒ¨λ”©μœΌλ‘œ 전체 ν…Œμ΄λΈ” 본문을 μ΄λ™ν•˜λ©΄ μ–΄λ–¨κΉŒμš”?

react-virtual을 μ‚¬μš©ν•˜λŠ” μ˜ˆμ—μ„œ https://codesandbox.io/s/poc-react-virtual-table-jyz0m

λ‚΄κ°€ μ›ν•˜λŠ” UXλ₯Ό 얻을 수 μžˆλ„λ‘ ν…Œμ΄λΈ”μ΄ μ ˆλŒ€μ μœΌλ‘œ ν•„μš”ν–ˆκ³  react-window μž‘λ™ν•˜λ„λ‘ λ§Œλ“œλŠ” ν•΄κ²° 방법에 λ§Œμ‘±ν•˜μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” 단지 virutalization λ‘œμ§μ„ ν›„ν¬λ‘œ μΆ”μΆœν•˜κ³  μœ„μ— κ²Œμ‹œ 된 것과 μœ μ‚¬ν•œ 두 개의 ν…Œμ΄λΈ”λ‘œ κ΅¬ν˜„ν–ˆμŠ΅λ‹ˆλ‹€. ν•˜λ‚˜λŠ” 헀더 용이고 λ‹€λ₯Έ ν•˜λ‚˜λŠ” μ½˜ν…μΈ  μš©μž…λ‹ˆλ‹€. λ‚΄ μ ‘κ·Ό λ°©μ‹μ˜ 차이점은 두 번째 ν…Œμ΄λΈ”μ—λŠ” μ—¬μ „νžˆ 마크 업에 헀더가 μžˆμ§€λ§Œ μ•‘μ„ΈμŠ€ ν•  수 μžˆλ„λ‘ μ‹œκ°μ μœΌλ‘œ μˆ¨κ²¨μ ΈμžˆλŠ” 반면 첫 번째 ν…Œμ΄λΈ”μ˜ ν—€λ”λŠ” λˆˆμ— λ„λŠ” μ‚¬μš©μžλ₯Ό μœ„ν•΄ μœ„μΉ˜μ— κ³ μ •λ˜μ–΄ μžˆλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. 맀λ ₯처럼 μž‘λ™ν•˜κ³ , μ½”λ“œλŠ” 훨씬 더 κ°„λ‹¨ν–ˆμŠ΅λ‹ˆλ‹€.

λˆ„κ΅°κ°€κ°€ 그것을 μ‹œλ„ν•˜κ³  싢을 경우λ₯Ό λŒ€λΉ„ν•˜μ—¬ κ·Έλƒ₯ 던져 λ²„λ¦¬μ‹­μ‹œμ˜€.

@piecyk virtuosoκ°€ κ΅¬ν˜„λ˜λŠ” 방식과 맀우 μœ μ‚¬ν•©λ‹ˆλ‹€. https://virtuoso.dev/grouped-by-first-letter/

μ ˆλŒ€ / μƒλ‹¨μœΌλ‘œ 전체 μ»¨ν…Œμ΄λ„ˆλ₯Ό λ°°μΉ˜ν•˜λŠ” 것이 μ„±λŠ₯이 λ›°μ–΄λ‚˜λ‹€λŠ” 것을 μΆ”κ°€ν•΄μ•Όν•˜μ§€λ§Œ Chrome으둜 μ„±λŠ₯ 감사λ₯Ό μ‹€ν–‰ν•˜λ©΄ FPS에 영ν–₯을 λ―ΈμΉ  μˆ˜μžˆλŠ” CLS λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€. λ‚˜λŠ” κ·Έ 영ν–₯이 λˆˆμ— 띄지 μ•ŠλŠ”λ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. https://b6udg.csb.app/ (큰 크기의 μ»¨ν…Œμ΄λ„ˆ μž„μ—λ„ λΆˆκ΅¬ν•˜κ³ )이 μ˜ˆμ œμ—μ„œ μ–Όλ§ˆλ‚˜ λΉ λ₯΄κ³  λΆ€λ“œλŸ¬μšΈ 수 μžˆλŠ”μ§€ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ padding-top / bottomμ—λŠ” CLSκ°€ μ—†μŠ΅λ‹ˆλ‹€!

λ‚˜λŠ” 이것을 직접 μ‹œλ„ν•˜κ³  μ‘°λ§Œκ°„ 차이λ₯Ό μΈ‘μ • ν•  κ²ƒμž…λ‹ˆλ‹€.

@pupudu μ €λŠ” μ—¬λŸ¬λΆ„μ˜ μ˜€ν”ˆ μ†ŒμŠ€ λ…Έλ ₯에 λ°•μˆ˜λ₯Ό

μ•„μ£Ό μž‘μ€ μ½”λ“œμ™€ λ§Žμ€ 창의λ ₯으둜 이것을 ν•΄λ‚Ό μˆ˜μžˆμ—ˆμŠ΅λ‹ˆλ‹€. μ½”λ“œλŠ” λˆ„κ΅¬λ‚˜ 볡사 / λΆ™μ—¬ λ„£κΈ° 및 μ›ν•˜λŠ”λŒ€λ‘œ ν™•μž₯ ν•  μˆ˜μžˆμ„λ§ŒνΌ κ°„λ‹¨ν•©λ‹ˆλ‹€. @bvaughn 방법 을 μ•Œμ•„ λ‚Έ ν›„ μ›ν•˜λŠ” 경우 λΌμ΄λΈŒλŸ¬λ¦¬μ— μΆ”κ°€ν•˜λŠ” 것은 맀우 μ‚¬μ†Œν•˜μ§€λ§Œ 방법을 μ•Œκ³  μžˆλ‹€λ©΄ μž¬μ •μ˜ν•˜λŠ” 것도 맀우 μ‚¬μ†Œν•©λ‹ˆλ‹€.

_ κ·Έκ²ƒμ˜ λΆ€μ‘± _ :

  • λ Œλ”λ§ ν›„ 첫 번째 ν–‰μ˜ "상단"μŠ€νƒ€μΌ 캑처
  • κ·Έ 값을 React.Context에 μ €μž₯ν•˜μ—¬ 전달할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • ν–‰ 자체 λŒ€μ‹  μ΄λ™λ˜λŠ” ν…Œμ΄λΈ” ꡬ성 μš”μ†Œμ— 값을 μ μš©ν•˜μ‹­μ‹œμ˜€.
  • 머리글 및 λ°”λ‹₯ κΈ€κ³Ό 같은 ν•­λͺ©μ— λŒ€ν•œ μΆ”κ°€ μŠ¬λ‘―μ„ μΆ”κ°€ν•˜μ‹­μ‹œμ˜€.
  • 라이브러리의 인체 곡학은 사물이 κΉ”λ”ν•˜κ²Œ μ „λ‹¬λ˜λŠ” 것을 ν—ˆμš©ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ React.ContextλŠ” ꡐ차 ꡬ성 μš”μ†Œ 톡신을 κ·Ήλ³΅ν•˜λŠ” μ˜μ›…μž…λ‹ˆλ‹€.

μž‘μ—… μ½”λ“œ μƒŒλ“œ λ°•μŠ€ : https://codesandbox.io/s/react-window-with-table-elements-d861o

μ°Έμ‘° 용 μ½”λ“œ

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')
)

κ°μ‚¬ν•©λ‹ˆλ‹€. InfiniteLoader ꡬ성 μš”μ†Œμ™€ ν•¨κ»˜ 이것을 μ‚¬μš©ν•˜λ €κ³  μ‹œλ„ν•œ μ‚¬λžŒμ΄ μžˆμŠ΅λ‹ˆκΉŒ (μ„±κ³΅μ μœΌλ‘œ)? ... λ‚˜λŠ” 그것을 μ‹œλ„ν–ˆμ§€λ§Œ λ‚΄λΆ€ "래퍼"에 λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€. λ¬΄ν•œ λ‘œλ”κ°€ 예기치 μ•Šμ€ propsλ₯Ό innerElementType에 μ „λ‹¬ν•˜κ³  있기 λ•Œλ¬Έμ΄λΌκ³  κ°€μ •ν•©λ‹ˆλ‹€.

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰