It is my understanding that refs are not defined outside the react lifecycle (source). The problem I am trying to solve is to capture a key press at the document level (i.e. trigger the event no matter what element is in focus), and then interact with a react ref. Below is a simplified example of what I am trying to do:
export default class Console extends React.Component {
constructor(props) {
super(props);
this.state = {
visible: false,
text: "",
};
}
print(output: string) {
this.setState({
text: this.state.text + output + "\n"
})
}
toggleVisible()
{
this.setState({visible: !this.state.visible});
}
render() {
const footer_style = {
display: this.state.visible ? "inline" : "none",
};
return (
<footer id="console-footer" className="footer container-fluid fixed-bottom" style={footer_style}>
<div className="row">
<textarea id="console" className="form-control" rows={5} readOnly={true}>{this.state.text}</textarea>
</div>
</footer>
);
}
}
class App extends React.Component {
private console: Console;
constructor() {
super({});
this.console = React.createRef();
}
keyDown = (e) =>
{
this.console.current.toggleVisible(); // <-- this is undefined
}
componentDidMount(){
document.addEventListener("keydown", this.keyDown);
},
componentWillUnmount() {
document.removeEventListener("keydown", this.keyDown);
},
render() {
return (
<div className="App" onKeyDown={this.keyDown}> // <-- this only works when this element is in focus
// other that has access to this.console that will call console.print(...)
<Console ref={this.console} />
</div>
);
}
}
My question is: is there a way to have this sort of document level key press within the lifesycle of react so that the ref is not undefined
inside the event handler keyDown
? I've seen a lot of solutions that involve setting the tabIndex
and hacking to make sure the proper element has focus at the right time, but these do not seem like robust solutions to me.
I'm just learning React so maybe this is a design limitation of React or I am not designing my components properly. But this sort of functionality seems quite basice to me, having the ability to pass components from one to the other and call methods on eachother.