如何在 setState 最终回调中获取 React 组件的最终提交状态?

问题描述 投票:0回答:1

我遇到了一些非常并发的情况,其中应用程序的状态发生变化以响应同时发生的许多不同事件,因此经典的

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?
        });
    });
}

基本上我的问题是如何通过启动状态更改,在通过回调发送到重新渲染之前获得最最终的状态?

reactjs
1个回答
0
投票

当涉及到哪些数据可用于当前渲染通道时,您的组件状态是唯一的权威。

但是,这并不意味着您不能继续跟踪状态变化并消除实际渲染触发器:

// 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>;
}
© www.soinside.com 2019 - 2024. All rights reserved.