子组件在父组件循环调用,子组件的数据是固定的,想做优化,这样做对吗?

问题1 子组件是个select ,数据都是从api获取,每次都是固定的内容。
父组件中的列表需要大量调用这个子组件,每次这个组件都需要调用api获取数据,每次数据都是一样,这个地方是不是需要优化?

问题2 如果需要优化的话,从react官网找了一下,简单做了更改,理论上每次excuteCallBack 是同一个引用,但是debug的时候 useEffect每次被调用没法证明excuteCallBack 是不是同一个引用呢?

理解不足,希望解答一下。

import React, { useCallback, useEffect, useState } from "react";
import { Team, User } from "@/type/user";
import { Select } from "antd";
import { getTeams } from "@/api";
const { Option } = Select;

interface Props {
  record: User;
}

const CusSelect: React.FC<Props> = ({ record }) => {
  const [teams, setTeams] = useState<Array<Team>>();

 const excuteCallBack = useCallback(
   () => {
    return getTeams()
   },
   []
 )
 

  useEffect(() => {
    console.log('excuteCallBack reference:',new Date(), excuteCallBack);
    async function excute() {
      try {
        let rest = await excuteCallBack();
        //debugger
        setTeams(rest.data);
      } catch (error) {
        console.log(error);
      }
    }
    excute();
  }, [excuteCallBack]);

  return (
    <Select
      className="w-4/5"
      defaultValue={record.team_name}
      disabled={record.role_name != "コーチ"}
      onChange={(value) => {
        alert(JSON.stringify(record) + value);
      }}
    >
      {teams?.map((item) => (
        <Option value={item.team_id} key={item.team_id}>
          {item.team_name}
        </Option>
      ))}
    </Select>
  );
};

export default CusSelect;
阅读 598
avatarAI BotBETA

问题1:是的,如果子组件的数据是固定的,并且每次父组件循环调用时都重新从API获取这些数据,那么这确实是一个可以优化的地方。因为每次获取相同的数据是不必要的,这会导致性能浪费和可能的延迟。

问题2:你的优化思路是正确的,使用useCallback来确保excuteCallBack在依赖项不变的情况下保持引用稳定,从而避免不必要的useEffect调用。然而,要验证excuteCallBack是否真的是同一个引用,你不能仅仅依赖console.log的输出,因为每次useEffect运行时,它都会打印出当前的引用和当前的时间戳,这并不能证明引用是否改变。

要验证excuteCallBack的引用是否改变,你可以尝试在父组件中记录每次CusSelect组件渲染时传入的excuteCallBack引用,并在多次渲染之间比较这些引用。如果引用确实保持不变,那么你的优化就是有效的。

此外,为了进一步优化,你可以考虑将API调用移到父组件中,并将获取到的数据作为属性传递给子组件。这样,子组件就可以避免不必要的API调用,并且只在数据发生变化时重新渲染。

下面是一个示例代码,展示了如何将API调用移到父组件中,并将数据作为属性传递给子组件:

import React, { useState, useEffect } from "react";
import { getTeams } from "@/api";
import CusSelect from "./CusSelect";

const ParentComponent = () => {
  const [teams, setTeams] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const rest = await getTeams();
        setTeams(rest.data);
      } catch (error) {
        console.log(error);
      }
    };

    fetchData();
  }, []); // 确保只在组件挂载时运行一次

  return (
    <div>
      {/* 假设你有一个列表需要渲染 */}
      {list.map((record) => (
        <CusSelect key={record.id} record={record} teams={teams} />
      ))}
    </div>
  );
};

export default ParentComponent;

然后,在CusSelect组件中,你可以直接使用传入的teams属性,而不再需要调用API:

const CusSelect: React.FC<Props> = ({ record, teams }) => {
  return (
    <Select
      className="w-4/5"
      defaultValue={record.team_name}
      disabled={record.role_name != "コーチ"}
      onChange={(value) => {
        alert(JSON.stringify(record) + value);
      }}
    >
      {teams.map((item) => (
        <Option value={item.team_id} key={item.team_id}>
          {item.team_name}
        </Option>
      ))}
    </Select>
  );
};

这样,你就可以避免在每次渲染CusSelect组件时都重新从API获取数据,从而提高性能。

1 个回答

先说问题1,确实可以优化一下,直接不发起请求,做个 fetch 的 cache 就完事了

第二个问题不太懂,但是我理解你做个节流触发 action,数据统一存在 store 就行

你这种缓存组件的操作应该都不大行。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题