μ΄κ²μ ν
μ΄λΈκ³Ό ν¨κ» μ¬μ©νλ μκ° μμ΅λκΉ? λλ κ·Έκ²μ΄ μλνλλ‘ λ
Έλ ₯νκ³ μμ§λ§ κ·Έκ²μ΄ μλνμ§ μκ±°λ λ΄κ° λκ°λ₯Ό λ§€μ° μλͺ»νκ³ μλ€λ κ°ν μμ¬μ κ°μ§κ³ μμ΅λλ€.
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>
λλ μ΄κ²μ΄ μ€μ λ‘ μλνμ§ μμ κ²μ΄λΌκ³ μκ°ν©λλ€. λ΄κ° μλ ν, 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 λ°©λ² μ μμ λΈ ν μνλ κ²½μ° λΌμ΄λΈλ¬λ¦¬μ μΆκ°νλ κ²μ λ§€μ° μ¬μνμ§λ§ λ°©λ²μ μκ³ μλ€λ©΄ μ¬μ μνλ κ²λ λ§€μ° μ¬μν©λλ€.
κ·Έκ²μ λΆμ‘± :
μμ μ½λ μλ λ°μ€ : 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
λ κ°μ§ λ¬Έμ κ° μμ΅λλ€.
미리 κ°μ¬λ립λλ€ :)
@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μ μ λ¬νκ³ μκΈ° λλ¬Έμ΄λΌκ³ κ°μ ν©λλ€.
κ°μ₯ μ μ©ν λκΈ
@pupudu μ λ μ¬λ¬λΆμ μ€ν μμ€ λ Έλ ₯μ λ°μλ₯Ό
μμ£Ό μμ μ½λμ λ§μ μ°½μλ ₯μΌλ‘ μ΄κ²μ ν΄λΌ μμμμ΅λλ€. μ½λλ λꡬλ λ³΅μ¬ / λΆμ¬ λ£κΈ° λ° μνλλλ‘ νμ₯ ν μμμλ§νΌ κ°λ¨ν©λλ€. @bvaughn λ°©λ² μ μμ λΈ ν μνλ κ²½μ° λΌμ΄λΈλ¬λ¦¬μ μΆκ°νλ κ²μ λ§€μ° μ¬μνμ§λ§ λ°©λ²μ μκ³ μλ€λ©΄ μ¬μ μνλ κ²λ λ§€μ° μ¬μν©λλ€.
κ·Έκ²μ λΆμ‘± :
μμ μ½λ μλ λ°μ€ : https://codesandbox.io/s/react-window-with-table-elements-d861o
μ°Έμ‘° μ© μ½λ