I am trying to use Reactstrap 8.5.1 innerRef attribute along with useRef() to focus the Input within a Modal whenever the Modal opens. The code below shows the Button which opens the Modal, but when clicked I get the error "Cannot read property 'focus' of null". It also writes inputRef to the console, which shows that .current is null.
I've tried various ways to set innerRef, but nothing seems to work. I'd be very grateful if someone can point out to me what I am missing.
import React, { useState, useRef, useEffect } from 'react';
import { Modal, ModalHeader, ModalBody, ModalFooter, Button, Input } from 'reactstrap';
export const ModalSave = (props) => {
const [modalIsOpen, setModalIsOpen] = useState(false);
const toggle = () => setModalIsOpen(!modalIsOpen);
const inputRef = useRef(null);
useEffect(() => {
console.log(inputRef);
if (modalIsOpen === true) {
inputRef.current.focus();
}
}, [modalIsOpen]);
return (
<div>
<Button
onClick={() => { setModalIsOpen(true); }}
>Save</Button>
<Modal isOpen={modalIsOpen} toggle={toggle}>
<ModalHeader toggle={toggle}>Save</ModalHeader>
<ModalBody>
Name:
<Input
innerRef={inputRef.current}
/>
</ModalBody>
<ModalFooter>
<Button>Save</Button>
<Button onClick={toggle}>Close</Button>
</ModalFooter>
</Modal>
</div>
);
}
The issue is that opening the modal doesn't trigger the component to re-render which is needed to get the input ref
value, and so, the ref
will remain null
unless some state is called to trigger the re-render. As a workaround, you can use setTimeout()
method to kind of force it like so:
useEffect(() => {
if (modalIsOpen) {
setTimeout(() => inputRef.current.focus(), 0);
}
}, [modalIsOpen]);
A better solution is to use the onOpened
method which is called after the modal has opened:
export default function App() {
const inputRef = useRef(null);
const [modalIsOpen, setModalIsOpen] = useState(false);
const toggle = () => setModalIsOpen(!modalIsOpen);
const handleOpen = () => inputRef.current.focus();
return (
<div className="App">
<div>
<Button onClick={() => setModalIsOpen(true)}>Save</Button>
<Modal isOpen={modalIsOpen} toggle={toggle} onOpened={handleOpen}>
<ModalHeader toggle={toggle}>Save</ModalHeader>
<ModalBody>
Name:
<Input innerRef={inputRef} />
</ModalBody>
<ModalFooter>
<Button>Save</Button>
<Button onClick={toggle}>Close</Button>
</ModalFooter>
</Modal>
</div>
</div>
);
}