为什么我的React子组件会重新渲染

时间:2020-09-02 12:38:51

标签: reactjs react-typescript

我有这个应用程序,我在其中加载页面加载时的大量数据,然后使用react-tables呈现表。每行都有一个“合规性”列,其中包含状态标签,用于说明是否符合要求。此列还包含一个按钮,按下该按钮可更新状态(queuedPortRecommendations),并为其提供建议的兼容值。

该表需要很长时间才能呈现,就像它在1400行左右时所期望的那样。但是我不知道为什么为什么在调用addQueuedChange函数时会重新渲染?

我尝试从addQueuedChange的deps数组中删除useMemo,但是没有将字符串添加到该数组中,而是将其替换了。

我知道很难得出一个直接的答案,但是任何提示或想法都将不胜感激。

App.tsx

const App = () => {
    const [data, setData] = useState<Port[]>([]);
    const [queuedPortRecommendations, setQueuedPortRecommendations] = useState<string[]>([]);
  
    useEffect(() => {
      const doFetch = async () => {
        const response = await fetch(`${BACKEND_BASE}/api/v1/ports?allData=false`);
        const body: BackendResponse  = await response.json()
        const { ports, portStats } = body.data;
        setData(ports);
      }
      doFetch()
    }, [data]);
  
    const addQueuedChange = (portRecommendation: string) => {
      setQueuedPortRecommendations([...queuedPortRecommendations, portRecommendation]);
    };
  
    const columns = useMemo(
      () => [
        {
          Header: 'Device name',
          accessor: 'device.hostname'
        },
        {
          Header: 'Compliance checks',
          accessor: (port: Port) => {
            return (
              <PortDescriptionRecommendation
                key={`${port.device}-${port.ifName}-port-recommendation`}
                port={port}
                addQueuedChange={addQueuedChange}
              />
            );
          },
        }
      ],
      [addQueuedChange]
    )
  
  return <TableContainer columns={columns} data={data} />;

PortDescriptionRecommendation

const PortDescriptionRecommendation = ({ port, addQueuedChange }: {port: Port, addQueuedChange:  (portRecommendation: string) => void }) => {

  const {remoteHostName, remotePort, tag, type} = port.portRecommendation;
  const remotePortDescription = remotePort ? ` (${remotePort})` : '';

  const handleAddToQueueButtonClicks = () => {
    addQueuedChange(portConfig);
  }

  let portConfig = `
conf t
interface ${port.ifName}
description ${tag}${remoteHostName || ''}${remotePortDescription}
end
wr mem`;

  return (
        <button data-tip={portConfig} className={'btn btn-sm btn-info'} onClick={handleAddToQueueButtonClicks}>
          Add recommendation to list
        </button>
   );
}

2 个答案:

答案 0 :(得分:1)

您应使用useCallback来避免重新渲染,每次更新应用程序状态时,都会创建一个新的addQueuedChange实例。这就是为什么。而且您不必将其添加到依赖关系数组中。

答案 1 :(得分:1)

首先,您要将useCallback添加到addQueuedChange,这样就不会在每个渲染上创建新的columns

尽管它可能无法完全解决问题: 当App组件重新呈现时。 TableContainer也被重新渲染。这是默认的React行为:更新parent时,它将重新渲染所有子代。要更改此行为,您应该使用React.memo

通常,在处理大表时,您想使用React.memo。根据我的经验,我通常也会记住表格的行。

确保addQueuedChange不依赖于portRecommendation

const addQueuedChange = useCallback(
  (portRecommendation: string) => {
    setQueuedPortRecommendations((prevPortRecommendation) => [
      ...prevPortRecommendation,
      portRecommendation,
    ]);
  },
  [setQueuedPortRecommendations]
);