在映射组件中使用 useRef / useImperativeHandle 的问题

问题描述 投票:0回答:4

我有一个包含不同组件的仪表板。一切都在每个组件上使用单独的启动按钮,现在我需要一个通用的启动按钮,并且为了从父级访问子级的子功能,我知道在 React 中你应该使用 useRef。(但它可能不是正确,但我正在努力寻找另一种方式)。我希望能够灵活地选择从这个“整体启动按钮”启动哪个组件

我有一个组件列表,我映射如下所示。

return(
{ComponentsList.map((item) => {
      return (
       <Showcomponents
        {...item}
        key={item.name}
       />
)

这很好用,但如前所述,我想在每个孩子中访问一个名为“buttonclick”的函数,所以我用压力计组件测试了这个

通过 forwardRef 和 useImparativeHandle“公开”的功能

const ShowRadialGauge = forwardRef((props, ref) => {
 useImperativeHandle(ref, () => ({
  buttonclick() {
   setStart(!start);
  },
 }));
)

然后在我的仪表板中我更改为:

const gaugepressure = useRef();

return(
  <div>
    <Button onClick={() => gaugepressure.current.buttonclick()}>
      Start processing
    </Button>
    <ShowRadialGauge ref={gaugepressure} />
  <div>
)

如果我使用仪表板中的 useRef 而不是映射组件,这很好用,我手动添加它们。

我知道 useRef 不是道具,但它几乎是我想要的。我想做这样的事情:

return(
{ComponentsList.map((item) => {
  return (
    <Showcomponents
      {...item}
      key={item.name}
      **ref={item.ref}**
   />
)

ref 可以是我的组件数组的一部分(如下所示)或单独的数组。

export const ComponentsList = [
 {
  name: "Radial gauge",
  text: "showradialgauge",
  component: ShowRadialGauge,
  ref: "gaugepressure",
 },
 {
  name: "Heatmap",
  text: "heatmap",
  component: Heatmap,
  ref: "heatmapstart",
 },
]

任何人有任何建议,或者换一种方式吗?

javascript reactjs react-hooks parent-child react-ref
4个回答
0
投票

你走在正确的轨道上,在父组件中有一个 React ref 附加到单个子组件。如果你映射到多个孩子,虽然你需要一个 React refs 数组,每个映射的孩子一个,并且在父级的按钮处理程序中,你将迭代 refs 数组以从每个调用公开的命令句柄。

例子:

家长

// Ref to hold all the component refs
const gaugesRef = React.useRef([]);

// set the ref's current value to be an array of mapped refs
// new refs to be created as needed
gaugesRef.current = componentsList.map(
  (_, i) => gaugesRef.current[i] ?? React.createRef()
);

const toggleAll = () => {
  // Iterate the array of refs and invoke the exposed handle
  gaugesRef.current.forEach((gauge) => gauge.current.toggleStart());
};

return (
  <div className="App">
    <button type="button" onClick={toggleAll}>
      Toggle All Gauges
    </button>
    {componentsList.map(({ name, component: Component, ...props }, i) => (
      <Component
        key={name}
        ref={gaugesRef.current[i]}
        name={name}
        {...props}
      />
    ))}
  </div>
);

孩子

const ShowRadialGauge = React.forwardRef(({ name }, ref) => {
  const [start, setStart] = React.useState(false);

  const toggleStart = () => setStart((start) => !start);

  React.useImperativeHandle(ref, () => ({
    toggleStart
  }));

  return (....);
});

Edit problems-using-useref-useimperativehandle-in-mapping-components

然而,实现此目的的更正确/React 方法是 将状态提升 到父组件并将状态和处理程序向下传递到这些组件。

家长

const [gaugeStarts, setGaugeStarts] = React.useState(
  componentsList.map(() => false)
);

const toggleAll = () => {
  setGaugeStarts((gaugeStarts) => gaugeStarts.map((start) => !start));
};

const toggleStart = (index) => {
  setGaugeStarts((gaugeStarts) =>
    gaugeStarts.map((start, i) => (i === index ? !start : start))
  );
};

return (
  <div className="App">
    <button type="button" onClick={toggleAll}>
      Toggle All Guages
    </button>
    {componentsList.map(({ name, component: Component, ...props },, i) => (
      <Component
        key={name}
        start={gaugeStarts[i]}
        toggleStart={() => toggleStart(i)}
        name={name}
        {...props}
      />
    ))}
  </div>
);

孩子

const ShowRadialGauge = ({ name, start, toggleStart }) => {
  return (
    <>
      ...
      <button type="button" onClick={toggleStart}>
        Toggle Start
      </button>
    </>
  );
};

Edit problems-using-useref-useimperativehandle-in-mapping-components (forked)


0
投票

@德鲁里斯

谢谢德鲁, 你当然是对的。我是 React 的新手,我正在努力思考这个“状态处理”。

我测试了你的建议,但正如你所说,它不是很“反应”,所以我将状态从孩子提升到父母。 在父母中:

const [componentstate, setComponentstate] = useState([
  { id:1, name: "pressuregauge", start: false},
  { id:2, name: "motormap", start: false },
  { id:3, name: "heatmapstart", start: false},
 ]);

然后在组件 ShowRadialGauge 中,我这样做了:

const ShowRadialGauge = ({ props, componentstate })

如果我们需要在每个组件中保留按钮,我在 componentstate 对象中有被解构的 id,所以我可以把它发回去。

.


0
投票

另一种实现方法是使用基于类的组件并使用 createRef,它将为每个孩子创建新的 ref。检查更多关于 useRef 和 createRef 之间的区别。


-1
投票

首先,当您可以通过 onClick 访问它时,为什么需要 refs 来处理点击。 React 中 refs 最常见的用例是引用 DOM 元素或存储在渲染之间持久存在的值

我的建议是这些

  • 首先,尝试通过传递一个函数使其变得简单,然后通过onClick触发它
  • 其次如果你真的想学习如何使用 imperativeHandle 你可以参考这个视频https://www.youtube.com/watch?v=zpEyAOkytkU.
© www.soinside.com 2019 - 2024. All rights reserved.