Skip to content

Commit f7bc8ac

Browse files
committed
chore: Init batch state
1 parent dedb5ad commit f7bc8ac

File tree

4 files changed

+79
-13
lines changed

4 files changed

+79
-13
lines changed

examples/basic.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ interface ItemType {
88
label: string;
99
}
1010

11+
const originConsole = console.log;
12+
1113
function createData(count: number): ItemType[] {
1214
const data: ItemType[] = new Array(count).fill(undefined).map((_, index) => ({
1315
value: index,

src/Overflow.tsx

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import classNames from 'classnames';
33
import ResizeObserver from 'rc-resize-observer';
44
import { getFullWidth } from './util';
55
import Item from './Item';
6+
import { useBatchState } from './hooks/useBatchState';
67

78
export interface OverflowProps<ItemType> {
89
prefixCls?: string;
@@ -30,11 +31,13 @@ function Overflow<ItemType = any>(
3031
maxCount = 'responsive',
3132
} = props;
3233

33-
const [containerWidth, setContainerWidth] = React.useState(0);
34-
const [itemWidths, setItemWidths] = React.useState(
34+
const createUseState = useBatchState();
35+
36+
const [containerWidth, setContainerWidth] = createUseState(0);
37+
const [itemWidths, setItemWidths] = createUseState(
3538
new Map<React.Key, number>(),
3639
);
37-
const [overflowWidth, setOverflowWidth] = React.useState(0);
40+
const [overflowWidth, setOverflowWidth] = createUseState(0);
3841

3942
const itemPrefixCls = `${prefixCls}-item`;
4043

@@ -60,23 +63,26 @@ function Overflow<ItemType = any>(
6063
}
6164

6265
function registerSize(key: React.Key, width: number) {
63-
const clone = new Map(itemWidths);
64-
console.log('==>>>', key, width);
65-
66-
if (!width) {
67-
clone.delete(key);
68-
} else {
69-
clone.set(key, width);
70-
}
71-
72-
setItemWidths(clone);
66+
setItemWidths((origin) => {
67+
const clone = new Map(origin);
68+
console.log('==>>>', key, width);
69+
70+
if (!width) {
71+
clone.delete(key);
72+
} else {
73+
clone.set(key, width);
74+
}
75+
return clone;
76+
});
7377
}
7478

7579
function registerOverflowSize(_: React.Key, width: number) {
7680
console.log('Overflow >>>', width);
7781
setOverflowWidth(width);
7882
}
7983

84+
console.log('BATCH >>>', containerWidth, overflowWidth, itemWidths);
85+
8086
// ================================ Render ================================
8187
let overflowNode = (
8288
<div className={classNames(prefixCls, className)} style={style} ref={ref}>

src/hooks/useBatchState.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { useRef, useState } from 'react';
2+
3+
/**
4+
* State generate. Return a `setState` but it will flush all state with one render to save perf.
5+
*/
6+
export function useBatchState() {
7+
const [, forceUpdate] = useState({});
8+
const statesRef = useRef<any[]>([]);
9+
let walkingIndex = 0;
10+
11+
function createState<T>(
12+
defaultValue: T,
13+
): [T, (value: T | ((origin: T) => T)) => void] {
14+
const myIndex = walkingIndex;
15+
walkingIndex += 1;
16+
17+
// Fill value if not exist yet
18+
if (statesRef.current.length < myIndex + 1) {
19+
statesRef.current[myIndex] = defaultValue;
20+
}
21+
22+
// Return filled as `setState`
23+
const value = statesRef.current[myIndex];
24+
25+
function setValue(val: any) {
26+
statesRef.current[myIndex] = typeof val === 'function' ? val(value) : val;
27+
28+
forceUpdate({});
29+
}
30+
31+
return [value, setValue];
32+
}
33+
34+
return createState;
35+
}

src/util.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,26 @@ export function getFullWidth(element: HTMLElement) {
1010

1111
return left + offsetWidth + right;
1212
}
13+
14+
// =================================== Frame ===================================
15+
let batchQueue: (() => void)[] = [];
16+
let batchUUID = 0;
17+
18+
/** Will execute all callback before next frame but after promise */
19+
export function batchTask(callback: () => void) {
20+
batchUUID += 1;
21+
const id = batchUUID;
22+
23+
batchQueue.push(callback);
24+
25+
const channel = new MessageChannel();
26+
channel.port1.onmessage = () => {
27+
if (id === batchUUID) {
28+
batchQueue.forEach((fn) => {
29+
fn();
30+
});
31+
batchQueue = [];
32+
}
33+
};
34+
channel.port2.postMessage(null);
35+
}

0 commit comments

Comments
 (0)