React. js Перехват useState вызывает слишком много повторных рендеров и не может обновить мое состояние. - PullRequest
0 голосов
/ 26 апреля 2020

Я студент, пытающийся освоить React. До сих пор я хотел бы иметь возможность разрезать массив данных, который я получаю от API, на куски, чтобы в дальнейшем можно было использовать эффект разбиения на страницы. Я не могу понять, почему функция arrayChunk () вызывает слишком много рендеров. Как можно установить для моей функции значение pu sh для 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;

Ответы [ 2 ]

0 голосов
/ 26 апреля 2020

В итоге вы вызываете arrayChunk каждый рендер, который устанавливает какое-то состояние и запускает повторный рендер. Использование ловушки эффектов для перерасчета массива chunked только тогда, когда activeYear обновления должны помочь.

useEffect(() => {
  activeYear.length > 6 && arrayChunk(activeYear, 6);
}, [activeYear]);

Затем просто визуализируйте { chunkedYearArray }

0 голосов
/ 26 апреля 2020

Каждый раз, когда вы вызываете 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;

В качестве альтернативы, если вы действительно хотите, чтобы оно было в состоянии, вы могли бы затем выполнить вычисление then из вызова API:

  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)
      );
  }, []);

Здесь определенно есть место для уборки, но я думаю, что любой из них выведет вас на правильный путь. Надеюсь, это поможет!

...