使用React Hooks时,如何处理父组件的function参数?

问题描述

这是一个演示:https://stackblitz.com/edit/react-ts-rttbjn

该演示正在按我的意愿运行。但是在PagingList.tsx中,将引发ESLint警告:

ESLint: React Hook useEffect has a missing dependency: 'loadAfter'. Either include it or remove the dependency array.(react-hooks/exhaustive-deps)

但是无法使用[loadAfter]

所以我很困惑,为什么loadAfter在重新渲染时会改变?最佳做法是什么?

PS:无法正常运行的演示,无限重新渲染:https://stackblitz.com/edit/react-ts-kl67zc

主要代码段:

PS:.eslintrc.js

// eslint-disable-next-line no-undef
module.exports = {
  root: true,parser: "@typescript-eslint/parser",plugins: ["@typescript-eslint","jest"],extends: [
    "eslint:recommended","plugin:@typescript-eslint/recommended","prettier/@typescript-eslint","plugin:react/recommended","plugin:react-hooks/recommended","plugin:jest/recommended",],settings: {
    react: {
      version: "16.13",},};

index.tsx

import React,{ FunctionComponent,useCallback } from "react";
import { PagingList } from "./PagingList";
import ReactDOM from "react-dom";

type Piece = {
  id: number;
};

const MAX_COUNT = 20;

async function getAfter(
  size: number,id?: number
): Promise<[Piece[],boolean]> {
  const from = Math.max(0,id || 0);
  const toExclusive = Math.min(from + size,MAX_COUNT);
  const items = Array.from({
    length: toExclusive - from,}).map((_,offset) => ({ id: from + offset + 1 }));
  return new Promise((resolve) =>
    setTimeout(() => resolve([items,toExclusive < MAX_COUNT]),1000)
  );
}

async function getBefore(
  size: number,boolean]> {
  const toExclusive = Math.max(0,(id || 0) - 1);
  const from = Math.max(toExclusive - size,0);
  const items = Array.from({
    length: toExclusive - from,from > 0]),1000)
  );
}

const App: FunctionComponent = () => {
  const Child = (piece: Piece) => (
    <div key={piece.id}>
      <span>Id: </span> {piece.id}
    </div>
  );

  const getAfterCallback = useCallback(
    (size: number,id?: number) => getAfter(size,id),[]
  );

  const getBeforeCallback = useCallback(
    (size: number,id?: number) => getBefore(size,[]
  );

  return (
    <PagingList
      childFunction={Child}
      getAfter={getAfterCallback}
      getBefore={getBeforeCallback}
    />
  );
};

ReactDOM.render(<App />,document.getElementById('root'));

PagingList.tsx [Workable but with error]

import React,{
  FunctionComponent,useCallback,useEffect,useState,} from "react";

const QUERY_SIZE = 10;

type Data = { id: number };

interface Props {
  childFunction: (data: Data) => JSX.Element;
  getAfter: (next: number,after?: number) => Promise<[Data[],boolean]>;
  getBefore: (last: number,before?: number) => Promise<[Data[],boolean]>;
}

export const PagingList: FunctionComponent<Props> = ({
  childFunction,getAfter,getBefore,}) => {
  const [after,setAfter] = useState<number | undefined>(undefined);
  const [before,setBefore] = useState<number | undefined>(undefined);
  const [data,setData] = useState<Data[]>([]);
  const [hasNext,setHasNext] = useState(false);
  const [hasLast,setHasLast] = useState(false);
  const [isLoading,setLoading] = useState(false);

  const loadAfter = useCallback(async () => {
    if (isLoading) {
      console.log("is loading");
      return;
    }

    setLoading(true);
    const [d,b] = await getAfter(QUERY_SIZE,after);
    setHasNext(b);
    setData(d);
    setAfter(d[d.length - 1].id);
    setBefore(d[0].id);
    setHasLast(true);
    setLoading(false);
  },[after,isLoading]);

  const loadBefore = useCallback(async () => {
    if (isLoading) {
      console.log("is loading");
      return;
    }

    setLoading(true);
    const [d,b] = await getBefore(QUERY_SIZE,before);
    setHasLast(b);
    setData(d);
    setAfter(d[d.length - 1].id);
    setBefore(d[0].id);
    setHasLast(true);
    setLoading(false);
  },[before,isLoading]);

  useEffect(() => {
    loadAfter();
    // ESLint: React Hook useEffect has a missing dependency: 'loadAfter'. Either include it or remove the dependency array.(react-hooks/exhaustive-deps)
    // But `[loadAfter]` as dep array is not working
  },[getAfter]);

  const body = () => {
    if (isLoading) {
      return <div>Loading...</div>;
    } else {
      return (
        <div>
          <div>{data.map((d) => childFunction(d))}</div>
          <button disabled={!hasLast} onClick={loadBefore}>
            Last Page
          </button>
          <button disabled={!hasNext} onClick={loadAfter}>
            Next Page
          </button>
        </div>
      );
    }
  };

  return body();
};

PagingList.tsx [Not Working but no warning]

import React,isLoading]);

  useEffect(() => {
    loadAfter();
    // Now re-render infinitely,but Now eslint warning
  },[loadAfter]);

  const body = () => {
    if (isLoading) {
      return <div>Loading...</div>;
    } else {
      return (
        <div>
          <div>{data.map((d) => childFunction(d))}</div>
          <button disabled={!hasLast} onClick={loadBefore}>
            Last Page
          </button>
          <button disabled={!hasNext} onClick={loadAfter}>
            Next Page
          </button>
        </div>
      );
    }
  };

  return body();
};

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)