我遇到了一些非常并发的情况,其中应用程序的状态发生变化以响应同时发生的许多不同事件,因此经典的
setState(state)
不起作用,我必须使用适用于未提交的
setState(state => { return {...state + extra } })
state(这意味着其他事件可以在用于下一次重新渲染之前对其添加更改),但同时我需要在提交状态时通过承诺返回一些结果(在所有并发更改都已完成之后)已应用于它),所以我去:
function applyChangesToState(param1, param2) {
return new Promise(resolve => {
this.setState(state => {
// some compuations here
const extra = calculateSomeExtra(state, param1, param2);
return {...state, extra };
, () => {
// HOW CAN I ACCESS THE COMMITED (MOST RECENT AND FINAL) STATE HERE?
const { extra } = state; // <-- WHERE SHOULD I READ THE COMMITTED STATE FROM?
// SO I CAN PUT IT IN RESOLVE:
resolve(extra);
// IF I READ FROM this.state HERE IS IT CERTAIN THAT
// ALL CONCURRENT CHANGES HAVE BEEN APPLIED ALREADY PRIOR TO
// THE NEXT RE-RENDER?
});
});
}
基本上我的问题是如何通过启动状态更改,在通过回调发送到重新渲染之前获得最最终的状态?
当涉及到哪些数据可用于当前渲染通道时,您的组件状态是唯一的权威。
但是,这并不意味着您不能继续跟踪状态变化并消除实际渲染触发器:
// You'd put this in its own file and then import it in your components:
export class Debouncer() {
state = {};
constructor(initialState, setState, interval = 500) {
this.setState = setState;
this.interval = interval;
this.lastRun = 0;
this.update(initialState);
}
update(data) {
// step 1: invalidate any already scheduled future update
clearTimeout(this.debounce);
// step 2: commit the change in this debouncer
Object.assign(this.state, data);
// step 3: do we trigger a setState now, or later?
const now = Date.now();
const delta = now - this.lastRun;
if (delta > this.interval) {
return this.send();
} else {
this.debounce = setTimeout(
() => this.send(),
this.interval
);
}
}
send() {
this.setState(this.state);
this.lastRun = Date.now();
}
}
然后导入它并将其用作数据处理程序,而不是直接 setState:
import { Debouncer } from "./wherever.js";
export function MyComponent(props) {
const [state, setState] = useState({});
useEffect(() => {
const debouncer = new Debouncer(state, setState, 250);
// even if this thing generates updates every millisecond,
// our component isn't going to update every millisecond,
// because we're not updating the component state, we're
// updating the debouncer state.
highFrequencyUpdatingAPI.listen(data => debouncer.update(data));
}, []);
return <div>{things based on state}</div>;
}