javascript - 刷新父组件时,防止子 React 组件中的下拉菜单关闭

标签 javascript reactjs react-hooks react-query tanstackreact-query

我对此做了一些研究,普遍的共识似乎是利用 useMemomemo React 组件,但我没有任何运气。

我有一个父 React 组件 (TypeScript),它还呈现一个自定义子组件,该子组件本质上创建一个 HTML select 标记。这一切都有效。但是,使用 TanStack 查询定期刷新父组件以显示新获取的信息。这种情况大约每秒发生一次。如果用户正在选择下拉列表中的项目,则发生这种情况时下拉列表将关闭并必须再次打开。不用说这很烦人。

我尝试了以下方法,但没有成功:

import { useState, useEffect, useRef, memo, useMemo } from "react";

function LogData(props: Props) {
  const [selectedUrl, setSelectedUrl] = useState<number>(0); // Tracks UI dropdown selection

  const theUrl = useMemo(
    () => ({ selectedUrl, setSelectedUrl }),
    [selectedUrl]
  );

  // This periodically executes the TanStack query which causes this component to rerender
  const { status, error, data, fetchStatus } = usePeriodicQuery(
    logUrl[selectedUrl],
    updateIntervalMs,
    "myQuery",
    isEnabled.current
  );

...additional code to parse the data...

  const MemoizedLogSelector = memo(LogSelector);

  return (
    <MemoizedLogSelector selectedUrlMemo={theUrl} />
    <TableContainer component={Paper}>
    ...table data code...
    </TableContainer>
 );

function LogSelector(props: {
  selectedUrlMemo: {
    selectedUrl: number,
    setSelectedUrl: React.Dispatch<React.SetStateAction<number>>,
  };
}) {
  console.warn(">>> LogSelector is rendering..."); // This is printing on every parent rerender
  return (
    <TextSelectInput
      label="Log Select:"
      labelFontSize="body1"
      labelPlacement="row"
      onChange={(value: number) => props.selectedUrlMemo.setSelectedUrl(value)}
      onClear={() => {}}
      options={[
        {
          label: "Message1",
          value: 0,
        },
        {
          label: "Message2",
          value: 1,
        },
        {
          label: "Message3",
          value: 2,
        },
      ]}
      value={props.selectedUrlMemo.selectedUrl}
    />
  );
}

这段代码有问题吗?或者有其他方法可以完成我正在寻找的事情吗?

最佳答案

const MemoizedLogSelector = memo(LogSelector);

问题是这行代码位于 LogData 的内部。因此,每次 logData 渲染时,您都会创建一个全新的 MemoizedLogSelector 组件。它可能具有与前一个相同的功能,但它是一个新的函数引用,因此它看起来像是一个不同的组件类型来使用react。因此,react 必须卸载旧的并安装新的,这会重置任何内部状态。

组件只能定义一次,因此请将代码行移到 LogData 之外:

const MemoizedLogSelector = memo(LogSelector);

function LogData(props: Props) {
  // ...
  return (
    <MemoizedLogSelector selectedUrlMemo={theUrl} />
    <TableContainer component={Paper}>
    ...table data code...
    </TableContainer>
 );
}

关于javascript - 刷新父组件时,防止子 React 组件中的下拉菜单关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77191425/

相关文章:

reactjs - 使用自定义 Hook 时重新渲染太多

javascript - JavaScript 的一秒真的是一秒吗?

javascript - 将动态数据从 API 绑定(bind)到 FlipView 控件

javascript - HTML/CSS/JS : Is it possible to find the element's size before appending it to the DOM tree?

javascript - useTransition - 对象不是函数或其返回值不可迭代

javascript - Flow js 不适用泛型

javascript - 从 map 外部动态显示传单标记弹出窗口

javascript - 在 createElement() 上 react 生命周期方法

javascript - 状态更新但不渲染

javascript - 我可以使用映射函数的索引作为包含动态不可预测文本的 React 组件的键吗?