【问题标题】:React.js useState hook causes too many re-renders and cant update my stateReact.js useState hook 导致过多的重新渲染并且无法更新我的状态
【发布时间】: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;

【问题讨论】:

    标签: reactjs react-hooks rerender use-state


    【解决方案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} alt="previous-page-button" />
          </button>
    
    
          <button className={style.rightArrow}>
            <img
              src={arrowButton}
              alt="next-page-button"
              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 }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-09
        • 1970-01-01
        • 1970-01-01
        • 2022-12-21
        • 2015-08-30
        • 1970-01-01
        • 2021-11-18
        • 2020-11-03
        相关资源
        最近更新 更多