React/reselect 如何在重新计算选择器之前刷新 ui

React/reselect how to refresh ui before a selector is recomputed

在我的 React-App (create-react-app) 中,我使用一个选择器(使用 reselect 创建)从存储的数据中计算派生数据。
问题是,选择器需要很长时间才能计算。我想在用户界面上显示微调器(或消息)。但是每次重新计算选择器时,ui 都会冻结。

我读了很多东西(Web Worker、requestIdleCallback、requestAnimationFrame)并尝试制作我自己的 React 钩子,但我被卡住了。我无法在回调中使用选择器。

搜索结果只是为了在重新计算选择器之前刷新ui。

这就是我的解决方案。我不知道它是否是 "good" 或者它是否违反了一些反应或重新选择的规则,但它有效。也许您可以评估一下?
代码已简化以提高可读性。

想法是,选择器 returns 一个 Promise,我在计算数据之前调用 requestAnimationFrame 以获得刷新 ui 的机会。

selector.js:

const dataSelector = state => state.data;

export const getDataComputedPromise = createSelector([dataSelector], (data) => {
    const compute = function () {
        return new Promise((resolve) => {
            // heavy computing stuff
            resolve(computedData);
        });
    };

    return new Promise((resolve) => {
        let start = null;
        let requestId = null;
        function step (timestamp) {
            if (!start) {
                start = timestamp;
                window.cancelAnimationFrame(requestId);
                requestId = window.requestAnimationFrame(step);
                return;
            };
            compute().then(freeResources => {
                window.cancelAnimationFrame(requestId);
                resolve(freeResources);
            });
        }
        requestId = window.requestAnimationFrame(step);
    });
});

myPage.js

const MyPage = ({ someProps }) => {
    ...
    const dataComputedPromise = useSelector(getDataComputedPromise);
    const [dataComputed, setDataComputed] = useState([]);
    const [computeSelector, setComputeSelector] = useState(false);
    useEffect(() => {
        setComputeSelector(true);
    }, [data]);
    useEffect(() => {
        dataComputedPromise.then(dataComputed => {
            setDataComputed(dataComputed);
            setComputeSelector(false);
        });
    }, [dataComputedPromise]);
    ...
    return <div>
        <Loader active={compueSelector}>Computing data...</Loader>
    </div>;
};

export default MyPage;