Reputation: 411
I have a component (Comp
) that I've added a useRef
(compRef
) to its parameters.
As part of the main useEffect - I'm setting the data of this component.
That data contains an array of strings, and the Comp
displaying all of them as input
s -
<Comp ref={compRef}>
<input type="text"/>
</Comp>
and
data = ["HIDDEN", "data1", "data2", "data3", "data4"]
useEffect(() => {
compRef.current.refElement.value = data;
}, []);
so now the Comp
will look like this -
<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>
I want to hide the first input with this hide
command -
compRef.current.refElement.children[0].style.display = "none";
The problem is, that with every method (useEffect) I'm using during the mount of the screen, the children are empty. Only after the screen is ready It's working (i.e. triggered by a <button>
)
I need a way to track the number of children of the ref before the view is mounted, and once it's greater than 1 to fire the hide
command.
How can I do that?
Upvotes: 6
Views: 2561
Reputation: 411
Ok
So after a lot of testing - the only option I found is to add setTimeout(() => compRef.current.refElement.children[0].style.display = "none")
after the render of the Comp
.
(After the render there is still only 1 child but the fact that the setTimeout is a-synchronic make it work)
Thank you all for the help :)
Upvotes: 3
Reputation: 55623
tldr - don't use refs to manipulate the DOM ever (unless you're an advanced react developer and know exactly what you're doing, which you aren't because these devs wouldn't be asking these questions on SO).
Don't use refs at all, you're doing React drastically wrong by manually manipulating the DOM.
Just pass the strings as props and let the component worry about displaying them:
const MyParentComponent = () => {
return <Comp data={["HIDDEN", "data1", "data2", "data3", "data4"]}/>
}
If you want to hide a certain input in that child component, then pass another prop, for example:
const MyParentComponent = () => {
const [indexToHide,setIndexToHide] = useState(0);
return <Comp data={["HIDDEN", "data1", "data2", "data3", "data4"]} indexOfInputToHide={indexToHide}/>
}
and then just let Comp
worry about it's props and that's it.
It's unclear what you're trying to do so the liklihood that this is the exact code you need is not great. But by continuing to try and use refs and manipulate the DOM, you are fighting against the framework and will end up having a much more difficult time in the future as you're doing react wrong, even if you do manage to come up with a working solution in this case.
Upvotes: 0
Reputation: 3130
I'm not sure if I've correctly understood the situation, but it seems odd to me.
Keep in mind that in React's paradigm, refs
are more like an escape hatch, and should be avoided when possible.
Also, beware that for non native components, a ref
can be forwarded to any element, or be handled in any way, so it is not safe to assume it will be the root element.
In any case, you may proceed as follows:
<Comp>
<input type="text" ref={(ref) => ref && (ref.parentElement.style.display = 'none')} />
</Comp>
It is the cleanest way I can think of right now with the information I have.
Please let me know if it works for you.
Update:
The function in ref
is called a Callback Ref. It will receive the corresponding ref
value as the first argument (the HTML input
element in this case).
The advantage is that you don't have to detect when Comp
decides to populate the DOM. The callback ref will be called as soon as the real node is ready.
Upvotes: 0