createAsyncThunk - 更改挂起状态不会导致立即重新渲染

createAsyncThunk - changing the state on pending doesn't cause immediate rerendering

我正在使用打字稿、useSelector 和@reduxjs/toolkit...

...当我调度 computeConfidenceIntervalsAsync 操作(参见下面的代码)时,我可以立即看到代码 运行ning 以下行: state.status = 'loading'

但是 ViewComponent 仅在 payloadCreator 完成 运行ning doSomeHeavyComputation 函数后才重新渲染。

用另一种方式解释:在 ViewComponent 中,我希望在繁重的计算之前呈现 'loading' 状态,但由于某种原因,繁重的计算首先是 运行,然后我收到 'loading' 和 'idle' 连续。

这方面有什么帮助吗?

减速器:

//...

export const computeConfidenceIntervalsAsync = createAsyncThunk(
  'forecast/getConfidenceIntervals',
  async (data: ConfidenceIntervalsParams) => {
    const response = await getConfidenceIntervals(data.totalRuns, data.itemsTarget, data.throughputs, new Date(data.startingDate));
    return [...response.entries()];
  }
);

export const forecastSlice = createSlice({
  name: 'forecast',
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(computeConfidenceIntervalsAsync.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(computeConfidenceIntervalsAsync.fulfilled, (state, action) => {
        state.status = 'idle';
        state.confidenceIntervals = action.payload;
      });
  }
});

export const selectForecast = (state: RootState) => state.forecast;
//...

服务:

//...
export function getConfidenceIntervals(totalRuns: number, itemsTarget: number, throughputs: number[], startingDate: Date) {
  return new Promise<Map<string, number>>((resolve) => {
    console.log('beginning');
    const outcomes = doSomeHeavyComputation(totalRuns, itemsTarget, throughputs, startingDate);
    console.log('ending');
    resolve(outcomes);
  });
}
//...

组件:

export function ViewComponent() {
  const forecast = useAppSelector(selectForecast);
  console.log(forecast)

  if (forecast.status === 'loading') {
    return (
      <div>Loading...</div>
    );
  }

  return (<div>...</div>);

使用选择器钩子

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import type { RootState, AppDispatch } from '../redux';

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

同步工作正在阻塞 - 而不是 cAT 的设计目的。 您可以通过执行

之类的操作来完成这项工作
export async function getConfidenceIntervals(totalRuns: number, itemsTarget: number, throughputs: number[], startingDate: Date) {
    await Promise.resolve() // this will defer this to the next tick, allowing React to render in-between
    console.log('beginning');
    const outcomes = doSomeHeavyComputation(totalRuns, itemsTarget, throughputs, startingDate);
    console.log('ending');
    return outcomes;
}

(我冒昧改写成async/await)

你的 promise 会立即开始,之前没有暂停,所以我添加了一个 await Promise.resolve() 来延迟执行。