(Refactor/Improve) 循环进行 API 调用并在 "no-loop-func" 之后操作数组

(Refactor/Improve) Loop to make API calls and manupilate Array following the "no-loop-func"

尽管在 Whosebug 上查看并遵循了许多答案,
我仍然未能重构此代码以遵守 ESLint no-loop-func

尽管我努力重构代码,但我不断收到以下警告:

Compiled with warnings.

Function declared in a loop contains unsafe references to variable(s) 'lastResult', 'biologyBooks', 'page'  no-loop-func

代码如下:

import React from 'react';
import { apiFullCall } from '../../apiHelper';

const MyComponent = props => {

  const [state, setState] = React.useState({ total: 0, biologyBooksByAuthor: [] });
  let isLoaded = React.useRef(true);

  const token = sessionStorage.getItem('token');
  const authorID = sessionStorage.getItem('author_id');
  
  const getBooks = async() => { // fetch items

    let page = 1;
    let scienceBooks, biologyBooks; 

    // create empty arrays to store book objects for each loop
    let scienceBooks = biologyBooks = [];

    // create a lastResult object to help check if there is a next page
    let lastResult = { next: null };


    do { // the looping - this is what I have failed to refactor
      try {
        await apiFullCall( // Make API calls over paginated records
          '', 
          token, 
          'get', 
          `books/?author_id=1&page=${page}` 
        ).then(res => {
          if (res) {
            const { status, body } = res;

            if (status === 200 || status === 201) {
              
              lastResult = body; // assign lastResult to pick "next"
    
              body && 
                body.results && 
                  body.results.map(eachBook => { // we map() over the returned "results" array

                      // the author with queried "author_id" writes science books; 
                      // so we add each book (an object) into the science category

                      scienceBooks.push(eachBook);

                      // We then filter the author's biology books (from other science books)

                      biologyBooks = scienceBooks.filter(
                        ({ is_biology }) =>
                          typeof(is_biology) === "boolean" && is_biology === true
                      );

                      return null;
                    }
              );

              // increment the page with 1 on each loop
              page++;
            }
          }
        }).catch(error => console.error('Error while fetching data:', error));

      } catch (err) { console.error(`Oops, something went wrong ${err}`); }

      // keep running until there's no next page
    } while (lastResult.next !== null);

    // update the state
    setState(prevState => ({
      ...prevState, total: scienceBooks.length, biologyBooksByAuthor: biologyBooks,
    }));
  };
  
  React.useEffect(() => { // fetch science books by author (logged in)

    if (isLoaded && authorID) {
      getBooks();
    };
    
    return function cleanup() {...}; // clean up API call, on unmount

  }, [isLoaded, authorID]);

  return (
     // render the JSX code
  );

}

请注意,我实际上在“do-while”之外声明了上述变量 lastResultbiologyBookspage

任何帮助或线索将不胜感激。

警告所指的函数是 .then 回调函数,如果您正在使用 async/await 坚持使用它,请尝试通过将结果分配给 a 来删除 .then 部分改为变量并删除不必要的 .map,您可以使用扩展运算符或 .concat.

连接以前的结果
import React from 'react';
import { apiFullCall } from '../../apiHelper';

const MyComponent = props => {
  const [state, setState] = React.useState({
    total: 0,
    scienceBooksByAuthor: [],
  });
  const isLoaded = React.useRef(true);

  const token = sessionStorage.getItem('token');
  const authorID = sessionStorage.getItem('author_id');

  const getBooks = async () => {
    // fetch items

    let page = 1;
    let scienceBooks = [];

    // create a lastResult object to help check if there is a next page
    let lastResult = { next: null };

    do {
      // the looping - this is what I have failed to refactor
      try {
        const res = await apiFullCall(
          // Make API calls over paginated records
          '',
          token,
          'get',
          `books/?author_id=1&page=${page}`,
        );
        if (res) {
          const { status, body } = res;

          if (status === 200 || status === 201) {
            lastResult = body; // assign lastResult to pick "next"

            // concatenate new results
            scienceBooks = [
              ...scienceBooks,
              ...((lastResult && lastResult.results) || []),
            ];

            // increment the page with 1 on each loop
            page += 1;
          }
        }
      } catch (err) {
        console.error(`Oops, something went wrong ${err}`);
      }

      // keep running until there's no next page
    } while (lastResult.next !== null);
    
    const biologyBooks = scienceBooks.filter(
      ({ is_biology }) =>
        typeof is_biology === 'boolean' && is_biology === true,
    );

    // update the state
    setState(prevState => ({
      ...prevState,
      total: scienceBooks.length,
      scienceBooksByAuthor: scienceBooks,
    }));
  };

  React.useEffect(() => {
    // fetch science books by author (logged in)

    if (isLoaded && authorID) {
      getBooks();
    }

    return function cleanup() {...}; // clean up API call, on unmount
  }, [isLoaded, authorID]);

  return (
    // render the JSX code
  );
};