Reputation: 3495
I have a simple modal:
renderModalForm() {
return (
<Modal
closeTimeoutMS={150}
show={this.state.isModalOpen}
onHide={this.isModalOpen.bind(this)}
>
<Modal.Body>
<div className="close-button-modal">
<i className="fa fa-times fa-2x pull-right" onClick={this.onButtonClick.bind(this)}></i>
<div className="clearfix"></div>
</div>
<div ref="test" className="testclassname">
</div>
</Modal.Body>
</Modal>
);
}
My sole objective is to inject a custom attribute (which unfortunately cannot start with data- or aria- since it's defined by third party) to the div
referenced by ref="test"
When I attempt to inject the custom attribute:
someButtonClicked() {
setTimeout(() => {
this.setState({
isModalOpen: true
})
}, 100);
var element = ReactDOM.findDOMNode(this.refs.test);
element.setAttribute('doku-div', 'form-payment');
}
Here element is always undefined, so setAttribute
failed; if I go inspect the element, ref="test"
does not exist at the <div>
! Can someone help me as to why this ref is missing inside modal?
Upvotes: 1
Views: 5519
Reputation: 806
The correct way to implement is use Callback hook. Whenever the component will render you will have the ref element. useCallback will also help stop unnecessary renders hence better performance.
const Parent = () => {
const [isVisible, setIsVisible] = useState(false);
return (
<>
<button onClick={() => setIsVisible(!isVisible)}>Show/Hide Popup</button>
<Child isVisible={isVisible} />
</>
);
};
const Child = () => {
const customRef = useCallback((ref) => {
// ref element accessible here
}, []);
return (
<Modal show={isVisible}>
<Modal.Body>
<input ref={customRef} type="text" />
</Modal.Body>
</Modal>
);
};
Upvotes: 3
Reputation: 126
useRef hook will not work in modals as the component will mount but the jsx will not render until you make show prop to true. useRef is asynchronous in nature thats why at the time of declaration it sets current to null but after you assign it to any element ref got value of it. But in case of modals the case is different. Here the elements are not registered instantly but after modal show prop is set to true
To solve this make the modal's show prop always to true and make whole component to show/hide dynamically similar query
Upvotes: 0
Reputation: 2223
Try moving your code to ComponentDidMount
or ComponentDidUpdate
method. Refs shouldn't be undefined there.
You can also use a callback to store a reference to the DOM node:
<Modal.Body>
<div className="close-button-modal">
<i className="fa fa-times fa-2x pull-right" onClick={this.onButtonClick.bind(this)}></i>
<div className="clearfix"></div>
</div>
<div ref="{(testNode) => { this.testNode = testNode; }}" className="testclassname">
</div>
</Modal.Body>
And then use that reference instead of using ReactDOM:
someButtonClicked() {
setTimeout(() => {
this.setState({
isModalOpen: true
})
}, 100);
var element = this.testNode;
this.testNode.setAttribute('doku-div', 'form-payment');
}
Upvotes: 0