✨ ADD simple react-window
This commit is contained in:
86
content/react-window/index.jsx
Normal file
86
content/react-window/index.jsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import "./styles.css";
|
||||
import styled from "styled-components";
|
||||
import { useState } from "react";
|
||||
|
||||
const LIST_LENGTH = 60;
|
||||
const FIXED_HEIGHT = 30;
|
||||
const TOTAL_HEIGHT = LIST_LENGTH * FIXED_HEIGHT;
|
||||
const WINDOW_HEIGHT = 300;
|
||||
const VISIBLE_ROW_NUM = Math.ceil(WINDOW_HEIGHT / FIXED_HEIGHT);
|
||||
const ADDITIONAL_ROW_NUM = 3;
|
||||
|
||||
function App() {
|
||||
const [currentWindow, setCurrentWindow] = useState([
|
||||
0,
|
||||
VISIBLE_ROW_NUM + ADDITIONAL_ROW_NUM,
|
||||
]);
|
||||
|
||||
const handleScroll = (e) => {
|
||||
requestAnimationFrame(() => {
|
||||
const currentScroll = e.target.scrollTop;
|
||||
setCurrentWindow(getVisibleIndexMap(currentScroll));
|
||||
});
|
||||
};
|
||||
|
||||
const getVisibleIndexMap = (currentScroll) => {
|
||||
const offset = Math.floor(currentScroll / FIXED_HEIGHT);
|
||||
const firstIndex =
|
||||
offset - ADDITIONAL_ROW_NUM < 0 ? 0 : offset - ADDITIONAL_ROW_NUM;
|
||||
|
||||
const mightLastIndex = firstIndex + VISIBLE_ROW_NUM + ADDITIONAL_ROW_NUM;
|
||||
const lastIndex =
|
||||
mightLastIndex <= LIST_LENGTH
|
||||
? mightLastIndex
|
||||
: mightLastIndex - ADDITIONAL_ROW_NUM <= LIST_LENGTH
|
||||
? mightLastIndex - ADDITIONAL_ROW_NUM
|
||||
: LIST_LENGTH;
|
||||
|
||||
return [firstIndex, lastIndex];
|
||||
};
|
||||
|
||||
const originList = [...Array(LIST_LENGTH)].map((el, index) => (
|
||||
<Row key={index} isEven={index % 2 === 0} top={index * FIXED_HEIGHT}>
|
||||
row {index + 1}
|
||||
</Row>
|
||||
));
|
||||
|
||||
const [firstIndex, lastIndex] = currentWindow;
|
||||
|
||||
return (
|
||||
<List onScroll={handleScroll}>
|
||||
<VirtualList>{originList.slice(firstIndex, lastIndex + 1)}</VirtualList>
|
||||
</List>
|
||||
);
|
||||
}
|
||||
|
||||
const List = styled.ul`
|
||||
height: ${WINDOW_HEIGHT}px;
|
||||
overflow: scroll;
|
||||
border: 3px solid #2ab1ac;
|
||||
box-shadow: 2px 2px 10px 2px lightgray;
|
||||
|
||||
padding: 0;
|
||||
`;
|
||||
|
||||
const VirtualList = styled.div`
|
||||
position: relative;
|
||||
height: ${TOTAL_HEIGHT}px;
|
||||
`;
|
||||
|
||||
const Row = styled.li`
|
||||
position: absolute;
|
||||
|
||||
width: 100%;
|
||||
height: ${FIXED_HEIGHT}px;
|
||||
top: ${({ top }) => top}px;
|
||||
left: 0;
|
||||
list-style: none;
|
||||
|
||||
background-color: ${({ isEven }) => isEven && "lightgray"};
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
export default App;
|
||||
Reference in New Issue
Block a user