我了解 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);
)
谢谢!
如果您使用 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);
});
您观察到的行为是 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;