如何避免每个 setState 渲染太多?

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

我了解 React Native 重新渲染调用 setState 的组件。 在我测试的示例中,useEffect 代码中每 7 个 setStates 有 7 个重新渲染:

  const pullData = async (numToPull, filterPull, sorterPull) => {
    setToSpin(true);
    const response = await AxiosPost(
      sc.Slink.getMailInbox,
      {
        page: 1,
        pageSize: numToPull,
        filterOption: [
          ...filterPull,
          {
            key: "isUnread",
            value: true,
          },
        ],
        sortOption: sorterPull,
      },
      { Authorization: ctxt.authInfo.tokenSF },
      { studio: ctxt.roomInfo.currentLoginRoom }
    );

    setToSpin(false);

    if (response.data.suc) {
      setShowList(response.data.data.items);
      setNumOfDataPulled(response.data.data.items.length);
      setSearchKey("");
      setCurrentFilter(filterPull);
      setCurrentSorter(sorterPull);
    } else setSmsg(response.data.msg);
  };

  useEffect(() => {
    pullData(sc.Snumber.numToPullMail, [], []);
  }, []);

我想知道这是 React Native 中设计的机制吗?还是有其他方法可以减少渲染时间?

上面的例子在我的项目中很简单——我有一些复杂的组件,其中使用了 20 多个 setState,每个组件中也有大约 10 个函数。如果 setState 导致重新渲染 20+ 次并重新创建函数,资源浪费可能相当大......

我不想使用 Redux、useCallback 并且想知道 1) 这在 React Native 世界中正常吗? (任何组件渲染 20 次); 2)是否有更聪明的方法来避免虚拟 DOM 比较中的资源浪费? (在上面的例子中,我没有看到任何理由必须为顺序编写的代码渲染组件 5 次

  setShowList(response.data.data.items);
  setNumOfDataPulled(response.data.data.items.length);
  setSearchKey("");
  setCurrentFilter(filterPull);
  setCurrentSorter(sorterPull);

)

谢谢!

reactjs react-native performance render setstate
2个回答
0
投票

如果您使用 React 18(在 React Native 0.69 中默认启用),像这样设置多个状态将只进行一次渲染:

setToSpin(false);

if (response.data.suc) {
  setShowList(response.data.data.items);
  setNumOfDataPulled(response.data.data.items.length);
  setSearchKey("");
  setCurrentFilter(filterPull);
  setCurrentSorter(sorterPull);
} else setSmsg(response.data.msg);

在 react 17 之前,react 可以通常将它们批处理在一起,但并非总是如此。其中一个不起作用的情况是您在示例中遇到的情况:在等待之后的异步函数中。对于这种情况,每次调用设置状态都会导致自己的渲染,而不是单个批处理。

在 React 17 中,您可以使用

unstable_batchedUpdates
:

强制对这些进行批处理
import { unstable_batchedUpdates } from 'react-native' // or in web, from 'react-dom'

// ...

unstable_batchedUpdates(() => {
  setToSpin(false);

  if (response.data.suc) {
    setShowList(response.data.data.items);
    setNumOfDataPulled(response.data.data.items.length);
    setSearchKey("");
    setCurrentFilter(filterPull);
    setCurrentSorter(sorterPull);
  } else setSmsg(response.data.msg);
});


0
投票

您观察到的行为是 React 和 React Native 的共同特征,称为“协调”。当组件的状态发生变化时,React 会检查组件的任何子元素是否需要重新渲染。如果需要更新任何子元素,则重新渲染整个组件。

在您提供的示例中,组件被重新渲染了 7 次,因为 pullData 函数中的 set 函数触发了 7 次状态更新。这是 React 和 React Native 中的正常行为,也是框架确保 UI 始终与应用程序状态保持同步的方式。

你可以通过 React.Memo 解决这个问题

import React, { memo, useEffect, useState } from 'react';

const MyComponent = memo(() => {
const [showList, setShowList] = useState([]);
const [numOfDataPulled, setNumOfDataPulled] = useState(0);
const [searchKey, setSearchKey] = useState("");
const [currentFilter, setCurrentFilter] = useState([]);
const [currentSorter, setCurrentSorter] = useState([]);
const [toSpin, setToSpin] = useState(false);

const pullData = async (numToPull, filterPull, sorterPull) => {
    setToSpin(true);
    const response = await AxiosPost(
        sc.Slink.getMailInbox,
        {
            page: 1,
            pageSize: numToPull,
            filterOption: [
                ...filterPull,
                {
                    key: "isUnread",
                    value: true,
                },
            ],
            sortOption: sorterPull,
        },
        { Authorization: ctxt.authInfo.tokenSF },
        { studio: ctxt.roomInfo.currentLoginRoom }
    );

    setToSpin(false);

    if (response.data.suc) {
        setShowList(response.data.data.items);
        setNumOfDataPulled(response.data.data.items.length);
        setSearchKey("");
        setCurrentFilter(filterPull);
        setCurrentSorter(sorterPull);
    } else setSmsg(response.data.msg);
};

useEffect(() => {
    pullData(sc.Snumber.numToPullMail, [], []);
}, []);

return (
    <div>
        // render your component here
    </div>
);
});

export default MyComponent;
© www.soinside.com 2019 - 2024. All rights reserved.