diff --git a/controller/index.js b/controller/index.js index 1cab29c..431716c 100644 --- a/controller/index.js +++ b/controller/index.js @@ -638,6 +638,24 @@ export default class Controller { return this.render() } disableBatchRefresh = true + + /** + * 同步触发 store 的 subscribe 回调,刷新视图 + * 类似于 react 18 的 flushSync + */ + flushSync(fn) { + if (this.disableBatchRefresh) { + fn() + return + } + this.disableBatchRefresh = true + try { + fn() + } finally { + this.disableBatchRefresh = false + } + } + bindStoreWithView() { let { context, store, history, meta } = this @@ -647,19 +665,23 @@ export default class Controller { } if (store) { - let refresh = (data) => { - if (meta.isDestroyed) return - this.refreshView && this.refreshView() - if (this.stateDidChange) { - this.stateDidChange(data) - } - } - - if (!this.disableBatchRefresh) { - refresh = _.debounce(refresh, 5) - } + let refresh = _.debounce( + ((data) => { + if (meta.isDestroyed) return + this.refreshView && this.refreshView() + if (this.stateDidChange) { + this.stateDidChange(data) + } + }), + 5 + ) - let unsubscribe = store.subscribe(refresh) + let unsubscribe = store.subscribe(data => { + refresh(data) + if (this.disableBatchRefresh) { + refresh.flush() + } + }) meta.unsubscribeList.push(unsubscribe) } diff --git a/package.json b/package.json index 6727dd2..bc7d839 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-imvc", - "version": "2.10.23", + "version": "2.10.24", "description": "An Isomorphic MVC Framework", "main": "./index", "bin": { diff --git a/project/src/batch-refresh/Controller.tsx b/project/src/batch-refresh/Controller.tsx index f245645..0f11121 100644 --- a/project/src/batch-refresh/Controller.tsx +++ b/project/src/batch-refresh/Controller.tsx @@ -24,10 +24,11 @@ export default class BatchRefreshController extends Controller { } } initialState = { - count: 0 + count: 0, + text: '' } // 选择是否禁用防抖刷新 - disableBatchRefresh: boolean = true + disableBatchRefresh: boolean = false handleIncre = () => { setTimeout(() => { // 重复调用多次,只会触发一次更新 @@ -39,31 +40,48 @@ export default class BatchRefreshController extends Controller { }) }, 0) } -} - - -function View({ state }: any) { - const ctrl = useCtrl() - const [count, setCount] = useState(0) - const handleIncre = () => { + handleIncreFlushSync = () => { setTimeout(() => { - setCount(count => count + 1) - setCount(count => count + 1) + this.flushSync(() => { + this.store.actions.UPDATE_STATE({ + count: this.store.getState().count + 1 + }) + this.store.actions.UPDATE_STATE({ + count: this.store.getState().count + 1 + }) + }) }, 0) + } + handleChange = (text: string) => { + this.flushSync(() => { + this.store.actions.UPDATE_STATE({ + text: text + }) + }) + } + +} + +function View({ state }: any) { + const ctrl = useCtrl() - console.log('render', state.count, count) + console.log('render', state.count, state.text) return (
{state.count}
- +
+ + ctrl.handleChange(e.target.value)} /> +
) } diff --git a/util/index.ts b/util/index.ts index a59716e..9686452 100644 --- a/util/index.ts +++ b/util/index.ts @@ -124,12 +124,22 @@ function getValueByPath(obj: objectOrArray, path: string | string[]) { return getPath(path).reduce(getValue, obj) } -function debounce(func: (data: T) => unknown, wait: number): typeof func { +function debounce(func: (data: T) => unknown, wait: number) { let timeout: ReturnType - return function (data: T) { + let currentFn: (() => void) | undefined + const flush = () => { clearTimeout(timeout) - timeout = setTimeout(() => { + currentFn?.() + currentFn = undefined + } + const debouncedFn = function (data: T) { + currentFn = () => { func(data) - }, wait) + } + timeout = setTimeout(flush, wait) } + + debouncedFn.flush = flush + + return debouncedFn } \ No newline at end of file