@noraent/nora-datagrid 0.0.50 → 0.0.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/App.js +8 -3
- package/lib/cjs/DataGrid.js +4 -0
- package/lib/cjs/buildPackage.json +1 -1
- package/lib/cjs/common/constants/utils.js +32 -12
- package/lib/cjs/components/TwoDimensionalVirtualizedList.js +27 -40
- package/lib/cjs/hooks/external/usePublicTest.js +2 -0
- package/lib/cjs/hooks/internal/useInternalPrivateApi.js +2 -1
- package/lib/cjs/provider/GridStoreContent.js +1 -1
- package/lib/cjs/types/dataGridProps.js +0 -1
- package/lib/esm/App.js +8 -3
- package/lib/esm/DataGrid.js +4 -0
- package/lib/esm/buildPackage.json +1 -1
- package/lib/esm/common/constants/utils.js +32 -12
- package/lib/esm/components/TwoDimensionalVirtualizedList.js +27 -40
- package/lib/esm/hooks/external/usePublicTest.js +2 -0
- package/lib/esm/hooks/internal/useInternalPrivateApi.js +2 -1
- package/lib/esm/provider/GridStoreContent.js +1 -1
- package/lib/esm/types/dataGridProps.js +0 -1
- package/package.json +1 -1
package/lib/cjs/App.js
CHANGED
|
@@ -24,7 +24,7 @@ const RenderCell = (params) => {
|
|
|
24
24
|
return {
|
|
25
25
|
id: i,
|
|
26
26
|
code: `${tt} -test-${i}`,
|
|
27
|
-
name: `name-${i}
|
|
27
|
+
name: `name-${i} `,
|
|
28
28
|
note: `note-${i}`,
|
|
29
29
|
date: new Date(),
|
|
30
30
|
currency4: `test-${i}`,
|
|
@@ -166,11 +166,11 @@ function App() {
|
|
|
166
166
|
const ref = useGridApiRef();
|
|
167
167
|
const [dataSource, setDataSource] = useState([]);
|
|
168
168
|
const handleDataSource = () => {
|
|
169
|
-
const data = Array.from({ length:
|
|
169
|
+
const data = Array.from({ length: 1000 }, (_, i) => {
|
|
170
170
|
return {
|
|
171
171
|
id: i,
|
|
172
172
|
code: `test-${i}`,
|
|
173
|
-
name: `name-${i}
|
|
173
|
+
name: `name-${i}`,
|
|
174
174
|
note: `note-${i}`,
|
|
175
175
|
date: new Date(),
|
|
176
176
|
currency4: `test=${i}`,
|
|
@@ -179,8 +179,13 @@ function App() {
|
|
|
179
179
|
// height: Math.floor(Math.random() * 20) + 20,
|
|
180
180
|
};
|
|
181
181
|
});
|
|
182
|
+
// requestIdleCallback(() => {
|
|
182
183
|
setDataSource(data);
|
|
184
|
+
// });
|
|
183
185
|
};
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
handleDataSource();
|
|
188
|
+
}, []);
|
|
184
189
|
return (_jsxs(_Fragment, { children: [_jsx("button", { onClick: () => {
|
|
185
190
|
ref.current.scrollToRowIndex(414);
|
|
186
191
|
}, children: "414 \uC774\uB3D9" }), _jsx("button", { onClick: () => {
|
package/lib/cjs/DataGrid.js
CHANGED
|
@@ -33,6 +33,7 @@ const DataGridMaster = React.forwardRef((props, _ref) => {
|
|
|
33
33
|
startTransition(() => {
|
|
34
34
|
apiRef.current.setGridContainer(containerRef);
|
|
35
35
|
apiRef.current.setInitialStore(props);
|
|
36
|
+
apiRef.current.initHeightCache();
|
|
36
37
|
});
|
|
37
38
|
}, []);
|
|
38
39
|
// 변경 된 부분만 반영
|
|
@@ -47,6 +48,9 @@ const DataGridMaster = React.forwardRef((props, _ref) => {
|
|
|
47
48
|
const basicStore = apiRef.current.setBasicStore(props);
|
|
48
49
|
apiRef.current.store.original[typedKey] = basicStore[typedKey];
|
|
49
50
|
apiRef.current.store.state[typedKey] = basicStore[typedKey];
|
|
51
|
+
if (key === "dataSource") {
|
|
52
|
+
apiRef.current.initHeightCache();
|
|
53
|
+
}
|
|
50
54
|
}
|
|
51
55
|
});
|
|
52
56
|
}
|
|
@@ -24,15 +24,24 @@ function useUpdateEffect(callback, deps) {
|
|
|
24
24
|
* @param callback 실행할 효과 함수
|
|
25
25
|
* @param dependencies 종속성 배열
|
|
26
26
|
*/
|
|
27
|
+
// export function useDeepCompareEffect<T>(callback: () => void | (() => void), dependencies: T[]): void {
|
|
28
|
+
// const previousDependenciesRef = React.useRef<T[] | undefined>();
|
|
29
|
+
// React.useEffect(() => {
|
|
30
|
+
// const isSame = _.isEqual(previousDependenciesRef.current, dependencies);
|
|
31
|
+
// if (!isSame) {
|
|
32
|
+
// previousDependenciesRef.current = _.cloneDeep(dependencies);
|
|
33
|
+
// return callback();
|
|
34
|
+
// }
|
|
35
|
+
// }, [callback, JSON.stringify(dependencies)]);
|
|
36
|
+
// }
|
|
27
37
|
export function useDeepCompareEffect(callback, dependencies) {
|
|
28
38
|
const previousDependenciesRef = React.useRef();
|
|
29
39
|
React.useEffect(() => {
|
|
30
|
-
|
|
31
|
-
if (!isSame) {
|
|
40
|
+
if (!_.isEqual(previousDependenciesRef.current, dependencies)) {
|
|
32
41
|
previousDependenciesRef.current = _.cloneDeep(dependencies);
|
|
33
42
|
return callback();
|
|
34
43
|
}
|
|
35
|
-
}, [callback
|
|
44
|
+
}, [callback]); // dependencies를 직접 참조하여 비교하므로 의존성 배열에서 제거
|
|
36
45
|
}
|
|
37
46
|
/**
|
|
38
47
|
* Array<Object> 경우 변경 감지하기 힘들기 때문에 별도 hook 구성함
|
|
@@ -41,20 +50,31 @@ export function useDeepCompareEffect(callback, dependencies) {
|
|
|
41
50
|
* @param deps 의존성 배열
|
|
42
51
|
* @returns 메모이제이션된 계산 결과
|
|
43
52
|
*/
|
|
53
|
+
// // 성능 문제로 비활성화
|
|
54
|
+
// // export function useDeepCompareMemo<T>(factory: () => T, deps: any[]): T {
|
|
55
|
+
// // // 의존성 배열을 위한 ref
|
|
56
|
+
// // const depsRef = React.useRef<any[]>();
|
|
57
|
+
// // // 현재 값을 저장하기 위한 ref
|
|
58
|
+
// // const valueRef = React.useRef<T>();
|
|
59
|
+
// // // 의존성의 깊은 비교 수행
|
|
60
|
+
// // const depsChanged = !_.isEqual(depsRef.current, deps);
|
|
61
|
+
// // // 의존성이 변경되었을 때만 값 재계산
|
|
62
|
+
// // if (depsChanged || valueRef.current === undefined) {
|
|
63
|
+
// // valueRef.current = factory();
|
|
64
|
+
// // depsRef.current = _.cloneDeep(deps);
|
|
65
|
+
// // }
|
|
66
|
+
// // // deps 배열의 얕은 비교를 위한 문자열화
|
|
67
|
+
// // // 이는 React의 렌더링 시스템과 함께 작동하기 위함
|
|
68
|
+
// // return React.useMemo(() => valueRef.current as T, [JSON.stringify(deps)]);
|
|
69
|
+
// // }
|
|
44
70
|
export function useDeepCompareMemo(factory, deps) {
|
|
45
|
-
// 의존성 배열을 위한 ref
|
|
46
71
|
const depsRef = React.useRef();
|
|
47
|
-
// 현재 값을 저장하기 위한 ref
|
|
48
72
|
const valueRef = React.useRef();
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
// 의존성이 변경되었을 때만 값 재계산
|
|
52
|
-
if (depsChanged || valueRef.current === undefined) {
|
|
73
|
+
// 의존성 배열을 깊은 비교하여 변경 여부 확인
|
|
74
|
+
if (!_.isEqual(depsRef.current, deps)) {
|
|
53
75
|
valueRef.current = factory();
|
|
54
76
|
depsRef.current = _.cloneDeep(deps);
|
|
55
77
|
}
|
|
56
|
-
|
|
57
|
-
// 이는 React의 렌더링 시스템과 함께 작동하기 위함
|
|
58
|
-
return React.useMemo(() => valueRef.current, [JSON.stringify(deps)]);
|
|
78
|
+
return valueRef.current;
|
|
59
79
|
}
|
|
60
80
|
export default useUpdateEffect;
|
|
@@ -36,7 +36,6 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
36
36
|
var _a;
|
|
37
37
|
const store = gridRef.current.store;
|
|
38
38
|
const parentElement = (_a = store === null || store === void 0 ? void 0 : store.gridContainer.current) === null || _a === void 0 ? void 0 : _a.parentElement;
|
|
39
|
-
// const parentElement = store?.gridContainer.current?.parentElement as HTMLDivElement;
|
|
40
39
|
// ResizeObserver 인스턴스 생성: 부모 요소의 크기 변화를 감지함
|
|
41
40
|
const observer = new ResizeObserver((entries) => {
|
|
42
41
|
for (let entry of entries) {
|
|
@@ -46,9 +45,8 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
46
45
|
// 새로운 자식 요소의 크기 계산
|
|
47
46
|
const newWidth = parentWidth;
|
|
48
47
|
const newHeight = parentHeight;
|
|
49
|
-
// if (windowSize.width !== newWidth || windowSize.height !== newHeight) {
|
|
50
48
|
// // 자식 요소의 현재 크기와 새 크기가 다른 경우, 크기를 업데이트
|
|
51
|
-
if (parentElement.style.height) {
|
|
49
|
+
if (parentElement.style.height || parentElement.style.maxHeight) {
|
|
52
50
|
setWindowSize({
|
|
53
51
|
width: newWidth,
|
|
54
52
|
height: newHeight,
|
|
@@ -60,27 +58,7 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
60
58
|
height: Math.max(initialWindowHeight, gridRef.current.store.state.dataSource.reduce((sum, item) => sum + item.height, 0) + 54),
|
|
61
59
|
});
|
|
62
60
|
}
|
|
63
|
-
// }
|
|
64
61
|
}
|
|
65
|
-
// const [entry] = entries;
|
|
66
|
-
// const observedHeight = entry.borderBoxSize && entry.borderBoxSize.length > 0 ? entry.borderBoxSize[0].blockSize : entry.contentRect.height;
|
|
67
|
-
// const observedWidth = entry.borderBoxSize && entry.borderBoxSize.length > 0 ? entry.borderBoxSize[0].blockSize : entry.contentRect.width;
|
|
68
|
-
// if (parentElement.style.height) {
|
|
69
|
-
// setWindowSize({
|
|
70
|
-
// width: observedWidth,
|
|
71
|
-
// height: observedHeight,
|
|
72
|
-
// });
|
|
73
|
-
// } else {
|
|
74
|
-
// console.log("@@@", parentElement, parentElement.style.height);
|
|
75
|
-
// // 부모 height 없을 경우
|
|
76
|
-
// setWindowSize({
|
|
77
|
-
// width: observedWidth,
|
|
78
|
-
// height: Math.max(
|
|
79
|
-
// initialWindowHeight,
|
|
80
|
-
// gridRef.current.store.state.dataSource.reduce((sum, item) => sum + item.height!, 0)
|
|
81
|
-
// ),
|
|
82
|
-
// });
|
|
83
|
-
// }
|
|
84
62
|
});
|
|
85
63
|
// const observer = new ResizeObserver((entries) => {
|
|
86
64
|
// // // 감지된 모든 요소에 대해 반복
|
|
@@ -124,14 +102,19 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
124
102
|
const { __randomDataSourceKey } = useSelector((store) => ({
|
|
125
103
|
__randomDataSourceKey: store.__randomDataSourceKey,
|
|
126
104
|
}));
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
105
|
+
const { cumulativeHeights } = useSelector((store) => ({
|
|
106
|
+
cumulativeHeights: store.cumulativeHeights,
|
|
107
|
+
}));
|
|
108
|
+
// 높이 계산 로직인데 dataSource깊은 복사를 통해 변경을 감지하여 다시 계산하기에는 성능 이슈가 발생할수있어. 수정 필요
|
|
109
|
+
//
|
|
110
|
+
// const totalHeight = useDeepCompareMemo(() => dataSource.reduce((sum, item) => sum + item.height!, 0), [dataSource]);
|
|
111
|
+
const totalHeight = useDeepCompareMemo(() => {
|
|
112
|
+
var _a, _b;
|
|
113
|
+
const heights = (_b = (_a = gridRef.current) === null || _a === void 0 ? void 0 : _a.store) === null || _b === void 0 ? void 0 : _b.cumulativeHeights;
|
|
114
|
+
if (!heights || heights.length === 0)
|
|
115
|
+
return 0;
|
|
116
|
+
return heights[heights.length - 1];
|
|
117
|
+
}, [cumulativeHeights]);
|
|
135
118
|
const totalWidth = useDeepCompareMemo(() => columns.reduce((sum, column) => sum + Number(column.width), 0) || 0, [columns]);
|
|
136
119
|
// const totalWidth = useMemo(() => columns.reduce((sum, column) => sum + Number(column.width), 0) || 0, [columns]);
|
|
137
120
|
const binarySearchIndex = useCallback((items, target) => {
|
|
@@ -151,13 +134,13 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
151
134
|
}
|
|
152
135
|
return Math.max(0, low - 1);
|
|
153
136
|
}, []);
|
|
154
|
-
const cumulativeHeights = useDeepCompareMemo(() => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}, [dataSource]);
|
|
137
|
+
// const cumulativeHeights = useDeepCompareMemo(() => {
|
|
138
|
+
// const heights = [0];
|
|
139
|
+
// for (let i = 0; i < dataSource.length; i++) {
|
|
140
|
+
// heights.push(heights[i] + dataSource[i].height!);
|
|
141
|
+
// }
|
|
142
|
+
// return heights;
|
|
143
|
+
// }, [dataSource]);
|
|
161
144
|
const cumulativeWidths = useDeepCompareMemo(() => {
|
|
162
145
|
const widths = [0];
|
|
163
146
|
for (let i = 0; i < columns.length || 0; i++) {
|
|
@@ -166,6 +149,7 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
166
149
|
return widths;
|
|
167
150
|
}, [columns]);
|
|
168
151
|
const getItemRange = useCallback(() => {
|
|
152
|
+
const dataSource = gridRef.current.store.state.dataSource;
|
|
169
153
|
const start = Math.max(0, binarySearchIndex(cumulativeHeights, scrollTop) - overscanTopRow);
|
|
170
154
|
let end = Math.min(start + overscanBottomRow, dataSource.length);
|
|
171
155
|
let startAdjust = start ? start + overscanTopRow : start;
|
|
@@ -175,7 +159,8 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
175
159
|
end = Math.min(end + overscanBottomRow, dataSource.length);
|
|
176
160
|
return { start, end };
|
|
177
161
|
}, [
|
|
178
|
-
|
|
162
|
+
// dataSource,
|
|
163
|
+
// JSON.stringify(dataSource),
|
|
179
164
|
scrollTop,
|
|
180
165
|
cumulativeHeights,
|
|
181
166
|
windowSize.height,
|
|
@@ -184,6 +169,7 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
184
169
|
]);
|
|
185
170
|
const { start, end } = getItemRange();
|
|
186
171
|
const visibleItems = useDeepCompareMemo(() => {
|
|
172
|
+
const dataSource = gridRef.current.store.state.dataSource;
|
|
187
173
|
const result = [];
|
|
188
174
|
const rowIndex = gridRef.current.getCellFocus()[0];
|
|
189
175
|
// 포함 안되어있으면 추가
|
|
@@ -200,8 +186,9 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
200
186
|
}
|
|
201
187
|
return result;
|
|
202
188
|
}, [
|
|
189
|
+
// totalHeight,
|
|
203
190
|
// __randomDataSourceKey,
|
|
204
|
-
dataSource,
|
|
191
|
+
// dataSource,
|
|
205
192
|
start,
|
|
206
193
|
end,
|
|
207
194
|
]);
|
|
@@ -23,9 +23,11 @@ export default function usePublicTest(apiRef) {
|
|
|
23
23
|
}, []);
|
|
24
24
|
const setRowHeight = React.useCallback((rowIndex, height = defaultProps.height) => {
|
|
25
25
|
apiRef.current.store.state.dataSource[rowIndex] = Object.assign(Object.assign({}, apiRef.current.store.state.dataSource[rowIndex]), { height: height });
|
|
26
|
+
apiRef.current.initHeightCache();
|
|
26
27
|
apiRef.current.store.__randomDataSourceKey = `${Math.random()}`;
|
|
27
28
|
apiRef.current.store.updateKeyTemp.add("state, dataSource");
|
|
28
29
|
apiRef.current.store.updateKeyTemp.add("__randomDataSourceKey");
|
|
30
|
+
apiRef.current.store.updateKeyTemp.add("cumulativeHeights");
|
|
29
31
|
setTimeout(() => {
|
|
30
32
|
apiRef.current.getPublicApi().forceUpdate();
|
|
31
33
|
}, 0);
|
|
@@ -125,6 +125,7 @@ export default function useInternalPrivateApi(apiRef) {
|
|
|
125
125
|
sum += (_a = row.height) !== null && _a !== void 0 ? _a : 32;
|
|
126
126
|
return sum;
|
|
127
127
|
});
|
|
128
|
+
heightCache[0] = 0;
|
|
128
129
|
apiRef.current.store.cumulativeHeights = heightCache;
|
|
129
130
|
return heightCache;
|
|
130
131
|
}, []);
|
|
@@ -134,7 +135,7 @@ export default function useInternalPrivateApi(apiRef) {
|
|
|
134
135
|
let result = 0;
|
|
135
136
|
while (low <= high) {
|
|
136
137
|
const mid = Math.floor((low + high) / 2);
|
|
137
|
-
if (mid
|
|
138
|
+
if (mid <= rowIndex) {
|
|
138
139
|
result = apiRef.current.store.cumulativeHeights[mid];
|
|
139
140
|
low = mid + 1;
|
|
140
141
|
}
|
|
@@ -89,7 +89,7 @@ export const useSelector = (selector) => {
|
|
|
89
89
|
const newPath = [...currentPath, prop];
|
|
90
90
|
const value = obj[prop];
|
|
91
91
|
// 정확한 경로 저장
|
|
92
|
-
if (currentPath.length > 0 || prop === "state" || prop === "original" || prop === "__randomDataSourceKey") {
|
|
92
|
+
if (currentPath.length > 0 || prop === "state" || prop === "original" || prop === "__randomDataSourceKey" || prop === "cumulativeHeights") {
|
|
93
93
|
if (!isArrayInSet(accessedPaths.current, newPath)) {
|
|
94
94
|
accessedPaths.current.add(newPath);
|
|
95
95
|
}
|
|
@@ -19,7 +19,6 @@ export class Store {
|
|
|
19
19
|
}
|
|
20
20
|
setState(path, value, isUpdate) {
|
|
21
21
|
const fullPath = Array.isArray(path) ? path.map(String) : [String(path)];
|
|
22
|
-
console.log(">>>>", fullPath);
|
|
23
22
|
this.state = this.updateNestedState(this.state, fullPath, value);
|
|
24
23
|
this.notify(fullPath, isUpdate);
|
|
25
24
|
}
|
package/lib/esm/App.js
CHANGED
|
@@ -24,7 +24,7 @@ const RenderCell = (params) => {
|
|
|
24
24
|
return {
|
|
25
25
|
id: i,
|
|
26
26
|
code: `${tt} -test-${i}`,
|
|
27
|
-
name: `name-${i}
|
|
27
|
+
name: `name-${i} `,
|
|
28
28
|
note: `note-${i}`,
|
|
29
29
|
date: new Date(),
|
|
30
30
|
currency4: `test-${i}`,
|
|
@@ -166,11 +166,11 @@ function App() {
|
|
|
166
166
|
const ref = useGridApiRef();
|
|
167
167
|
const [dataSource, setDataSource] = useState([]);
|
|
168
168
|
const handleDataSource = () => {
|
|
169
|
-
const data = Array.from({ length:
|
|
169
|
+
const data = Array.from({ length: 1000 }, (_, i) => {
|
|
170
170
|
return {
|
|
171
171
|
id: i,
|
|
172
172
|
code: `test-${i}`,
|
|
173
|
-
name: `name-${i}
|
|
173
|
+
name: `name-${i}`,
|
|
174
174
|
note: `note-${i}`,
|
|
175
175
|
date: new Date(),
|
|
176
176
|
currency4: `test=${i}`,
|
|
@@ -179,8 +179,13 @@ function App() {
|
|
|
179
179
|
// height: Math.floor(Math.random() * 20) + 20,
|
|
180
180
|
};
|
|
181
181
|
});
|
|
182
|
+
// requestIdleCallback(() => {
|
|
182
183
|
setDataSource(data);
|
|
184
|
+
// });
|
|
183
185
|
};
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
handleDataSource();
|
|
188
|
+
}, []);
|
|
184
189
|
return (_jsxs(_Fragment, { children: [_jsx("button", { onClick: () => {
|
|
185
190
|
ref.current.scrollToRowIndex(414);
|
|
186
191
|
}, children: "414 \uC774\uB3D9" }), _jsx("button", { onClick: () => {
|
package/lib/esm/DataGrid.js
CHANGED
|
@@ -33,6 +33,7 @@ const DataGridMaster = React.forwardRef((props, _ref) => {
|
|
|
33
33
|
startTransition(() => {
|
|
34
34
|
apiRef.current.setGridContainer(containerRef);
|
|
35
35
|
apiRef.current.setInitialStore(props);
|
|
36
|
+
apiRef.current.initHeightCache();
|
|
36
37
|
});
|
|
37
38
|
}, []);
|
|
38
39
|
// 변경 된 부분만 반영
|
|
@@ -47,6 +48,9 @@ const DataGridMaster = React.forwardRef((props, _ref) => {
|
|
|
47
48
|
const basicStore = apiRef.current.setBasicStore(props);
|
|
48
49
|
apiRef.current.store.original[typedKey] = basicStore[typedKey];
|
|
49
50
|
apiRef.current.store.state[typedKey] = basicStore[typedKey];
|
|
51
|
+
if (key === "dataSource") {
|
|
52
|
+
apiRef.current.initHeightCache();
|
|
53
|
+
}
|
|
50
54
|
}
|
|
51
55
|
});
|
|
52
56
|
}
|
|
@@ -24,15 +24,24 @@ function useUpdateEffect(callback, deps) {
|
|
|
24
24
|
* @param callback 실행할 효과 함수
|
|
25
25
|
* @param dependencies 종속성 배열
|
|
26
26
|
*/
|
|
27
|
+
// export function useDeepCompareEffect<T>(callback: () => void | (() => void), dependencies: T[]): void {
|
|
28
|
+
// const previousDependenciesRef = React.useRef<T[] | undefined>();
|
|
29
|
+
// React.useEffect(() => {
|
|
30
|
+
// const isSame = _.isEqual(previousDependenciesRef.current, dependencies);
|
|
31
|
+
// if (!isSame) {
|
|
32
|
+
// previousDependenciesRef.current = _.cloneDeep(dependencies);
|
|
33
|
+
// return callback();
|
|
34
|
+
// }
|
|
35
|
+
// }, [callback, JSON.stringify(dependencies)]);
|
|
36
|
+
// }
|
|
27
37
|
export function useDeepCompareEffect(callback, dependencies) {
|
|
28
38
|
const previousDependenciesRef = React.useRef();
|
|
29
39
|
React.useEffect(() => {
|
|
30
|
-
|
|
31
|
-
if (!isSame) {
|
|
40
|
+
if (!_.isEqual(previousDependenciesRef.current, dependencies)) {
|
|
32
41
|
previousDependenciesRef.current = _.cloneDeep(dependencies);
|
|
33
42
|
return callback();
|
|
34
43
|
}
|
|
35
|
-
}, [callback
|
|
44
|
+
}, [callback]); // dependencies를 직접 참조하여 비교하므로 의존성 배열에서 제거
|
|
36
45
|
}
|
|
37
46
|
/**
|
|
38
47
|
* Array<Object> 경우 변경 감지하기 힘들기 때문에 별도 hook 구성함
|
|
@@ -41,20 +50,31 @@ export function useDeepCompareEffect(callback, dependencies) {
|
|
|
41
50
|
* @param deps 의존성 배열
|
|
42
51
|
* @returns 메모이제이션된 계산 결과
|
|
43
52
|
*/
|
|
53
|
+
// // 성능 문제로 비활성화
|
|
54
|
+
// // export function useDeepCompareMemo<T>(factory: () => T, deps: any[]): T {
|
|
55
|
+
// // // 의존성 배열을 위한 ref
|
|
56
|
+
// // const depsRef = React.useRef<any[]>();
|
|
57
|
+
// // // 현재 값을 저장하기 위한 ref
|
|
58
|
+
// // const valueRef = React.useRef<T>();
|
|
59
|
+
// // // 의존성의 깊은 비교 수행
|
|
60
|
+
// // const depsChanged = !_.isEqual(depsRef.current, deps);
|
|
61
|
+
// // // 의존성이 변경되었을 때만 값 재계산
|
|
62
|
+
// // if (depsChanged || valueRef.current === undefined) {
|
|
63
|
+
// // valueRef.current = factory();
|
|
64
|
+
// // depsRef.current = _.cloneDeep(deps);
|
|
65
|
+
// // }
|
|
66
|
+
// // // deps 배열의 얕은 비교를 위한 문자열화
|
|
67
|
+
// // // 이는 React의 렌더링 시스템과 함께 작동하기 위함
|
|
68
|
+
// // return React.useMemo(() => valueRef.current as T, [JSON.stringify(deps)]);
|
|
69
|
+
// // }
|
|
44
70
|
export function useDeepCompareMemo(factory, deps) {
|
|
45
|
-
// 의존성 배열을 위한 ref
|
|
46
71
|
const depsRef = React.useRef();
|
|
47
|
-
// 현재 값을 저장하기 위한 ref
|
|
48
72
|
const valueRef = React.useRef();
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
// 의존성이 변경되었을 때만 값 재계산
|
|
52
|
-
if (depsChanged || valueRef.current === undefined) {
|
|
73
|
+
// 의존성 배열을 깊은 비교하여 변경 여부 확인
|
|
74
|
+
if (!_.isEqual(depsRef.current, deps)) {
|
|
53
75
|
valueRef.current = factory();
|
|
54
76
|
depsRef.current = _.cloneDeep(deps);
|
|
55
77
|
}
|
|
56
|
-
|
|
57
|
-
// 이는 React의 렌더링 시스템과 함께 작동하기 위함
|
|
58
|
-
return React.useMemo(() => valueRef.current, [JSON.stringify(deps)]);
|
|
78
|
+
return valueRef.current;
|
|
59
79
|
}
|
|
60
80
|
export default useUpdateEffect;
|
|
@@ -36,7 +36,6 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
36
36
|
var _a;
|
|
37
37
|
const store = gridRef.current.store;
|
|
38
38
|
const parentElement = (_a = store === null || store === void 0 ? void 0 : store.gridContainer.current) === null || _a === void 0 ? void 0 : _a.parentElement;
|
|
39
|
-
// const parentElement = store?.gridContainer.current?.parentElement as HTMLDivElement;
|
|
40
39
|
// ResizeObserver 인스턴스 생성: 부모 요소의 크기 변화를 감지함
|
|
41
40
|
const observer = new ResizeObserver((entries) => {
|
|
42
41
|
for (let entry of entries) {
|
|
@@ -46,9 +45,8 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
46
45
|
// 새로운 자식 요소의 크기 계산
|
|
47
46
|
const newWidth = parentWidth;
|
|
48
47
|
const newHeight = parentHeight;
|
|
49
|
-
// if (windowSize.width !== newWidth || windowSize.height !== newHeight) {
|
|
50
48
|
// // 자식 요소의 현재 크기와 새 크기가 다른 경우, 크기를 업데이트
|
|
51
|
-
if (parentElement.style.height) {
|
|
49
|
+
if (parentElement.style.height || parentElement.style.maxHeight) {
|
|
52
50
|
setWindowSize({
|
|
53
51
|
width: newWidth,
|
|
54
52
|
height: newHeight,
|
|
@@ -60,27 +58,7 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
60
58
|
height: Math.max(initialWindowHeight, gridRef.current.store.state.dataSource.reduce((sum, item) => sum + item.height, 0) + 54),
|
|
61
59
|
});
|
|
62
60
|
}
|
|
63
|
-
// }
|
|
64
61
|
}
|
|
65
|
-
// const [entry] = entries;
|
|
66
|
-
// const observedHeight = entry.borderBoxSize && entry.borderBoxSize.length > 0 ? entry.borderBoxSize[0].blockSize : entry.contentRect.height;
|
|
67
|
-
// const observedWidth = entry.borderBoxSize && entry.borderBoxSize.length > 0 ? entry.borderBoxSize[0].blockSize : entry.contentRect.width;
|
|
68
|
-
// if (parentElement.style.height) {
|
|
69
|
-
// setWindowSize({
|
|
70
|
-
// width: observedWidth,
|
|
71
|
-
// height: observedHeight,
|
|
72
|
-
// });
|
|
73
|
-
// } else {
|
|
74
|
-
// console.log("@@@", parentElement, parentElement.style.height);
|
|
75
|
-
// // 부모 height 없을 경우
|
|
76
|
-
// setWindowSize({
|
|
77
|
-
// width: observedWidth,
|
|
78
|
-
// height: Math.max(
|
|
79
|
-
// initialWindowHeight,
|
|
80
|
-
// gridRef.current.store.state.dataSource.reduce((sum, item) => sum + item.height!, 0)
|
|
81
|
-
// ),
|
|
82
|
-
// });
|
|
83
|
-
// }
|
|
84
62
|
});
|
|
85
63
|
// const observer = new ResizeObserver((entries) => {
|
|
86
64
|
// // // 감지된 모든 요소에 대해 반복
|
|
@@ -124,14 +102,19 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
124
102
|
const { __randomDataSourceKey } = useSelector((store) => ({
|
|
125
103
|
__randomDataSourceKey: store.__randomDataSourceKey,
|
|
126
104
|
}));
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
105
|
+
const { cumulativeHeights } = useSelector((store) => ({
|
|
106
|
+
cumulativeHeights: store.cumulativeHeights,
|
|
107
|
+
}));
|
|
108
|
+
// 높이 계산 로직인데 dataSource깊은 복사를 통해 변경을 감지하여 다시 계산하기에는 성능 이슈가 발생할수있어. 수정 필요
|
|
109
|
+
//
|
|
110
|
+
// const totalHeight = useDeepCompareMemo(() => dataSource.reduce((sum, item) => sum + item.height!, 0), [dataSource]);
|
|
111
|
+
const totalHeight = useDeepCompareMemo(() => {
|
|
112
|
+
var _a, _b;
|
|
113
|
+
const heights = (_b = (_a = gridRef.current) === null || _a === void 0 ? void 0 : _a.store) === null || _b === void 0 ? void 0 : _b.cumulativeHeights;
|
|
114
|
+
if (!heights || heights.length === 0)
|
|
115
|
+
return 0;
|
|
116
|
+
return heights[heights.length - 1];
|
|
117
|
+
}, [cumulativeHeights]);
|
|
135
118
|
const totalWidth = useDeepCompareMemo(() => columns.reduce((sum, column) => sum + Number(column.width), 0) || 0, [columns]);
|
|
136
119
|
// const totalWidth = useMemo(() => columns.reduce((sum, column) => sum + Number(column.width), 0) || 0, [columns]);
|
|
137
120
|
const binarySearchIndex = useCallback((items, target) => {
|
|
@@ -151,13 +134,13 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
151
134
|
}
|
|
152
135
|
return Math.max(0, low - 1);
|
|
153
136
|
}, []);
|
|
154
|
-
const cumulativeHeights = useDeepCompareMemo(() => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}, [dataSource]);
|
|
137
|
+
// const cumulativeHeights = useDeepCompareMemo(() => {
|
|
138
|
+
// const heights = [0];
|
|
139
|
+
// for (let i = 0; i < dataSource.length; i++) {
|
|
140
|
+
// heights.push(heights[i] + dataSource[i].height!);
|
|
141
|
+
// }
|
|
142
|
+
// return heights;
|
|
143
|
+
// }, [dataSource]);
|
|
161
144
|
const cumulativeWidths = useDeepCompareMemo(() => {
|
|
162
145
|
const widths = [0];
|
|
163
146
|
for (let i = 0; i < columns.length || 0; i++) {
|
|
@@ -166,6 +149,7 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
166
149
|
return widths;
|
|
167
150
|
}, [columns]);
|
|
168
151
|
const getItemRange = useCallback(() => {
|
|
152
|
+
const dataSource = gridRef.current.store.state.dataSource;
|
|
169
153
|
const start = Math.max(0, binarySearchIndex(cumulativeHeights, scrollTop) - overscanTopRow);
|
|
170
154
|
let end = Math.min(start + overscanBottomRow, dataSource.length);
|
|
171
155
|
let startAdjust = start ? start + overscanTopRow : start;
|
|
@@ -175,7 +159,8 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
175
159
|
end = Math.min(end + overscanBottomRow, dataSource.length);
|
|
176
160
|
return { start, end };
|
|
177
161
|
}, [
|
|
178
|
-
|
|
162
|
+
// dataSource,
|
|
163
|
+
// JSON.stringify(dataSource),
|
|
179
164
|
scrollTop,
|
|
180
165
|
cumulativeHeights,
|
|
181
166
|
windowSize.height,
|
|
@@ -184,6 +169,7 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
184
169
|
]);
|
|
185
170
|
const { start, end } = getItemRange();
|
|
186
171
|
const visibleItems = useDeepCompareMemo(() => {
|
|
172
|
+
const dataSource = gridRef.current.store.state.dataSource;
|
|
187
173
|
const result = [];
|
|
188
174
|
const rowIndex = gridRef.current.getCellFocus()[0];
|
|
189
175
|
// 포함 안되어있으면 추가
|
|
@@ -200,8 +186,9 @@ const DynamicVirtualScroll = React.memo(({ children }) => {
|
|
|
200
186
|
}
|
|
201
187
|
return result;
|
|
202
188
|
}, [
|
|
189
|
+
// totalHeight,
|
|
203
190
|
// __randomDataSourceKey,
|
|
204
|
-
dataSource,
|
|
191
|
+
// dataSource,
|
|
205
192
|
start,
|
|
206
193
|
end,
|
|
207
194
|
]);
|
|
@@ -23,9 +23,11 @@ export default function usePublicTest(apiRef) {
|
|
|
23
23
|
}, []);
|
|
24
24
|
const setRowHeight = React.useCallback((rowIndex, height = defaultProps.height) => {
|
|
25
25
|
apiRef.current.store.state.dataSource[rowIndex] = Object.assign(Object.assign({}, apiRef.current.store.state.dataSource[rowIndex]), { height: height });
|
|
26
|
+
apiRef.current.initHeightCache();
|
|
26
27
|
apiRef.current.store.__randomDataSourceKey = `${Math.random()}`;
|
|
27
28
|
apiRef.current.store.updateKeyTemp.add("state, dataSource");
|
|
28
29
|
apiRef.current.store.updateKeyTemp.add("__randomDataSourceKey");
|
|
30
|
+
apiRef.current.store.updateKeyTemp.add("cumulativeHeights");
|
|
29
31
|
setTimeout(() => {
|
|
30
32
|
apiRef.current.getPublicApi().forceUpdate();
|
|
31
33
|
}, 0);
|
|
@@ -125,6 +125,7 @@ export default function useInternalPrivateApi(apiRef) {
|
|
|
125
125
|
sum += (_a = row.height) !== null && _a !== void 0 ? _a : 32;
|
|
126
126
|
return sum;
|
|
127
127
|
});
|
|
128
|
+
heightCache[0] = 0;
|
|
128
129
|
apiRef.current.store.cumulativeHeights = heightCache;
|
|
129
130
|
return heightCache;
|
|
130
131
|
}, []);
|
|
@@ -134,7 +135,7 @@ export default function useInternalPrivateApi(apiRef) {
|
|
|
134
135
|
let result = 0;
|
|
135
136
|
while (low <= high) {
|
|
136
137
|
const mid = Math.floor((low + high) / 2);
|
|
137
|
-
if (mid
|
|
138
|
+
if (mid <= rowIndex) {
|
|
138
139
|
result = apiRef.current.store.cumulativeHeights[mid];
|
|
139
140
|
low = mid + 1;
|
|
140
141
|
}
|
|
@@ -89,7 +89,7 @@ export const useSelector = (selector) => {
|
|
|
89
89
|
const newPath = [...currentPath, prop];
|
|
90
90
|
const value = obj[prop];
|
|
91
91
|
// 정확한 경로 저장
|
|
92
|
-
if (currentPath.length > 0 || prop === "state" || prop === "original" || prop === "__randomDataSourceKey") {
|
|
92
|
+
if (currentPath.length > 0 || prop === "state" || prop === "original" || prop === "__randomDataSourceKey" || prop === "cumulativeHeights") {
|
|
93
93
|
if (!isArrayInSet(accessedPaths.current, newPath)) {
|
|
94
94
|
accessedPaths.current.add(newPath);
|
|
95
95
|
}
|
|
@@ -19,7 +19,6 @@ export class Store {
|
|
|
19
19
|
}
|
|
20
20
|
setState(path, value, isUpdate) {
|
|
21
21
|
const fullPath = Array.isArray(path) ? path.map(String) : [String(path)];
|
|
22
|
-
console.log(">>>>", fullPath);
|
|
23
22
|
this.state = this.updateNestedState(this.state, fullPath, value);
|
|
24
23
|
this.notify(fullPath, isUpdate);
|
|
25
24
|
}
|