React.js useState hook 导致过多的重新渲染并且无法更新我的状态
Posted
技术标签:
【中文标题】React.js useState hook 导致过多的重新渲染并且无法更新我的状态【英文标题】:React.js useState hook causes too many re-renders and cant update my state 【发布时间】:2020-08-09 17:53:12 【问题描述】:我是一名试图掌握 React 窍门的学生。到目前为止,我希望能够将从 API 接收的数据数组切割成块,以便以后可以使用分页效果。我无法弄清楚为什么函数 arrayChunk() 最终会导致过多的渲染。如何设置我的函数以将 chunkedArray 推入 setChunkedYearArray? 这是我的完整代码:
import React, useState, useEffect from 'react';
import InformationBox from '../../component/InformationBox/InformationBox';
import arrowButton from '../../assets/arrow-button.svg';
const InformationBoxLayout = (props) =>
const [activeYear, setActiveYear] = useState([]);
const [chunkedYearArray, setChunkedYearArray] = useState([]);
useEffect(() =>
axios
.get('http://www.mocky.io/v2/5ea446a43000005900ce2ca3')
.then((response) =>
setActiveYear(
response.data.timelineInfo.filter((item) => item.year === '2018')
)
);
, []);
const arrayChunk = (array, chunkSize) =>
const chunkedArray = [];
let clonedArray = [...array];
const splitPieces = Math.ceil(clonedArray.length / chunkSize);
for (let i = 0; i < splitPieces; i++)
chunkedArray.push(clonedArray.splice(0, chunkSize));
setChunkedYearArray(chunkedArray);
;
return (
<div className=style.infoBoxLayoutStyle>
<button className=style.leftArrow>
<img src=arrowButton alt='previous-page-button' />
</button>
activeYear.length > 6
? arrayChunk(activeYear, 6)
: console.log('no split')
<button className=style.rightArrow>
<img
src=arrowButton
alt='next-page-button'
className=style.rotateArrowRight
/>
</button>
</div>
);
;
export default InformationBoxLayout;
【问题讨论】:
【参考方案1】:任何时候你调用 setState 组件都会重新渲染,所以你不能在渲染函数中调用 setState。没有理由为chunkedYearArray
使用状态。只需从函数返回值,然后使用它:
const InformationBoxLayout = props =>
const [activeYear, setActiveYear] = useState([]);
useEffect(() =>
axios
.get("http://www.mocky.io/v2/5ea446a43000005900ce2ca3")
.then(response =>
setActiveYear(
response.data.timelineInfo.filter(item => item.year === "2018")
)
);
, []);
const arrayChunk = (array, chunkSize) =>
const chunkedArray = [];
let clonedArray = [...array];
const splitPieces = Math.ceil(clonedArray.length / chunkSize);
for (let i = 0; i < splitPieces; i++)
chunkedArray.push(clonedArray.splice(0, chunkSize));
return chunkedArray;
;
// Now you have calculated it, so use it for whatever you want in your JSX
const chunkedYearArray = activeYear.length > 6
? arrayChunk(activeYear, 6)
: [];
return (
<div className=style.infoBoxLayoutStyle>
<button className=style.leftArrow>
<img src=arrowButton />
</button>
<button className=style.rightArrow>
<img
src=arrowButton
className=style.rotateArrowRight
/>
</button>
</div>
);
;
export default InformationBoxLayout;
或者,如果您真的希望它处于状态,您可以通过 API 调用在 then
中进行计算:
const [chunkedYearArray, setChunkedYearArray] = useState([]);
useEffect(() =>
axios
.get("http://www.mocky.io/v2/5ea446a43000005900ce2ca3")
.then(response =>
setActiveYear(
response.data.timelineInfo.filter(item => item.year === "2018")
)
const arrayChunk = (array, chunkSize) =>
const chunkedArray = [];
let clonedArray = [...array];
const splitPieces = Math.ceil(clonedArray.length / chunkSize);
for (let i = 0; i < splitPieces; i++)
chunkedArray.push(clonedArray.splice(0, chunkSize));
return chunkedArray;
;
const newChunkedYearArray = activeYear.length > 6 ? arrayChunk(activeYear, 6)
: [];
// Because we are in useEffect we are only calculated once!
setChunkedYearArray(newChunkedYearArray)
);
, []);
这里肯定有清理的余地,但我认为其中任何一个都会让你走上正轨。希望对您有所帮助!
【讨论】:
【参考方案2】:您最终会调用arrayChunk
每个渲染设置一些状态并触发重新渲染。仅当 activeYear
更新应该有帮助时,才使用效果挂钩重新计算分块数组。
useEffect(() =>
activeYear.length > 6 && arrayChunk(activeYear, 6);
, [activeYear]);
然后只渲染 chunkedYearArray
【讨论】:
以上是关于React.js useState hook 导致过多的重新渲染并且无法更新我的状态的主要内容,如果未能解决你的问题,请参考以下文章
为啥我没有取回 useState 的新值 - React.JS?