我有一个包含不同组件的仪表板。一切都在每个组件上使用单独的启动按钮,现在我需要一个通用的启动按钮,并且为了从父级访问子级的子功能,我知道在 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",
},
]
任何人有任何建议,或者换一种方式吗?
你走在正确的轨道上,在父组件中有一个 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 (....);
});
然而,实现此目的的更正确/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>
</>
);
};
@德鲁里斯
谢谢德鲁, 你当然是对的。我是 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,所以我可以把它发回去。
.
另一种实现方法是使用基于类的组件并使用 createRef,它将为每个孩子创建新的 ref。检查更多关于 useRef 和 createRef 之间的区别。
首先,当您可以通过 onClick 访问它时,为什么需要 refs 来处理点击。 React 中 refs 最常见的用例是引用 DOM 元素或存储在渲染之间持久存在的值
我的建议是这些