React - 如何跟踪 useRef 中子元素的变化

6

我有一个组件(Comp),我已经在它的参数中添加了一个useRefcompRef)。 作为主要的useEffect的一部分,我正在设置这个组件的数据。 这个数据包含一个字符串数组,而Comp将所有这些字符串显示为

<Comp ref={compRef}>
     <input type="text"/>
</Comp>

并且
data = ["HIDDEN", "data1", "data2", "data3", "data4"]

useEffect(() => { 
     compRef.current.refElement.value = data;
}, []);

现在Comp的代码将如下所示 -

<Comp>
<generatedWrap> // should be hidden
    <input value="HIDDEN" />
</generatedWrap>

<generatedWrap>
    <input value="data1" />
</generatedWrap>

<generatedWrap>
    <input value="data2" />
</generatedWrap>

<generatedWrap>
    <input value="data3" />
</generatedWrap>

<generatedWrap>
    <input value="data4" />
</generatedWrap>
</Comp>

我希望您使用“隐藏”命令来隐藏第一个输入框 -
compRef.current.refElement.children[0].style.display = "none";

问题在于,使用每种方法(useEffect)在屏幕挂载期间,子元素是空的。只有在屏幕准备就绪后才能工作(例如通过<button>触发)。
我需要一种方法,在视图挂载之前跟踪ref的子元素数,一旦大于1,就触发hide命令。
我该怎么做?

请问您能否发布“Comp”和主要组件(在其中使用“Comp”)的完整代码? - Ernesto Stifano
除了根据“data”和传递的子元素生成输入列表之外,Comp是否有任何特殊功能? - Ernesto Stifano
你希望输入框何时可见/隐藏?有什么逻辑依据吗? - Ernesto Stifano
@ErnestoStifano 感谢您的评论 - Comp 为输入生成了一个漂亮的框架,并在每个输入附近添加了 + 和垃圾按钮。隐藏的逻辑是因为 Comp 不支持删除最后一个输入,所以我在开头放了一个虚拟输入,计划将其隐藏,这样我就可以删除最后一个(/第二个)输入。 - Dvi N
虚拟输入将是<input type="text"/>吗?所以,Comp将其子元素呈现为生成的输入框的兄弟节点? - Ernesto Stifano
显示剩余2条评论
3个回答

3

经过大量测试后,我发现唯一的选择是在Comp渲染后添加setTimeout(() => compRef.current.refElement.children[0].style.display = "none")

(渲染后仍然只有1个子元素,但由于setTimeout是异步的,所以它可以正常工作)

感谢大家的帮助 :)


0

tldr - 永远不要使用 ref 来操作 DOM(除非你是高级 React 开发者并且知道自己在做什么,但你不是,因为这些开发者不会在 SO 上提出这些问题)。

完全不要使用 refs,通过手动操作 DOM 来进行 React 开发是非常错误的。

只需将字符串作为 props 传递,并让组件负责显示它们:

const MyParentComponent = () => {

   return <Comp data={["HIDDEN", "data1", "data2", "data3", "data4"]}/>
}

如果你想在子组件中隐藏某个输入,那么可以传递另一个属性,例如:

const MyParentComponent = () => {

   const [indexToHide,setIndexToHide] = useState(0);

   return <Comp data={["HIDDEN", "data1", "data2", "data3", "data4"]} indexOfInputToHide={indexToHide}/>
}

然后只需让Comp担心它的props,就这样。

不清楚你想做什么,所以这可能不是你需要的确切代码。但是,如果继续尝试使用refs和操作DOM,你将与框架对抗,并且在未来会遇到更困难的问题,因为你正在错误地使用React,即使在这种情况下你设法找到了一个可行的解决方案。


嗨,谢谢你的回答和建议!:) - 不幸的是,我无法向Comp传递任何其他参数。Comp是外部组件,无法更改。唯一的选择是在其渲染后手动更改DOM... - Dvi N

0

我不确定我是否正确理解了情况,但对我来说这似乎有些奇怪。

请记住,在React的范式中,refs更像是一个逃生通道,应尽量避免使用。

此外,请注意对于非原生组件,ref可以被转发到任何元素,或以任何方式处理,因此不能安全地假设它将是根元素。

无论如何,您可以按照以下步骤进行:

<Comp>
     <input type="text" ref={(ref) => ref && (ref.parentElement.style.display = 'none')} />
</Comp>

这是我目前可以想到的最清晰的方式,根据我所掌握的信息。

如果对您有用,请告诉我。

更新:

ref 中的函数被称为 Callback Ref。它将接收相应的 ref 值作为第一个参数(在本例中为 HTML input 元素)。

优点是你不必检测何时 Comp 决定填充 DOM。当真实节点准备好时,回调 ref 将被调用。


你说了一些非常重要的东西。关于解决方案 - 将会有几个输入(比如我的新编辑),我只想隐藏第一个输入。将函数作为ref参数传递具体意味着什么? - Dvi N
我刚刚更新了我的回答。对于几个输入的疑问,我仍然不明白。<generatedWrap>是由您还是由Comp添加的?其他输入是由您还是由Comp添加的?我建议您只在第一个输入中添加ref={(ref) => ref.parentElement.style.display = 'none'} - Ernesto Stifano
我只写了1个Comp和1个inputComp添加了generatedWrap和所有其他input - Dvi N
顺便说一下,我已经在输入框中添加了ref={(ref) => ref.parentElement.style.display = 'none'},但它抛出了一个ref=null的错误... 我进行了调试,在第一次调用函数时它是正常的,但第二次却出现了null异常。 - Dvi N
@DviN 抱歉,这是因为组件卸载时ref被传递为null。请尝试以下操作并让我知道结果:ref={(ref) => ref && ref.parentElement.style.display = 'none'}。我会相应地更新我的答案。 - Ernesto Stifano
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接