I have an input element, that is rendered depending on condition.
render() {
const {
isNameInputVisible,
name
} = this.state;
return (
<div>
{isNameInputVisible ? (
<input
onChange={this.handleNameChange}
ref={this.nameInput}
type="text"
value={name}
/>
) : (
<h1
className="list-header__heading"
onClick={this.handleNameInputVisibility}
>
{name}
</h1>
)}
</div>
)
Basically, I want to listen for a click on the document, to hide the input whenever user click's outside this input element.
Right now I'm doing this:
componentDidMount() {
document.addEventListener('mousedown', this.handleClick);
}
handleClick = event => {
//do some logic
};
But I've been wondering if this is the correct way, because the event exists and fires, even when the element is not rendered.
So I've tried this:
componentDidUpdate () {
const {isNameInputVisible} = this.state;
isNameInputVisible && document.addEventListener('mousedown', this.handleClick);
}
But it doesn't work.
Question 1: What is the right way of attaching events to document when it depends on other conditionally rendered elements??
Question 2: What is the correct way of attaching events, for example, like escape press, for closing dialogs that o etc??
答案 0 :(得分:0)
仅当存在条件渲染的元素的ref时,才需要在componentDidMount
方法中添加事件侦听器。您可以使用this.refName.current
来确定ref是否已附加到元素。
这里最重要的是input
元素拥有自己的生命周期方法,而不是与更大的组件共享它们。通过使用自己的生命周期方法将input
元素移动到其自己的组件,这些方法将仅在input
的创建和删除过程中触发。
// App.jsx
import React from "react"
import ReactDOM from "react-dom"
import CustomInput from "./CustomInput"
class App extends React.Component {
constructor(props) {
super(props)
this.inputRef = React.createRef()
this.toggleInput = this.toggleInput.bind(this)
this.state = {
inputVisible: false
}
}
toggleInput(e) {
this.setState(prevState => ({
inputVisible: !prevState.inputVisible
}))
}
render() {
const { inputVisible } = this.state
return (
<div>
<input type="button" value="toggle input" onClick={this.toggleInput} />
{ inputVisible
? <CustomInput />
: <p>Input is not visible</p>
}
</div>
)
}
}
const rootElement = document.getElementById("root")
ReactDOM.render(<App />, rootElement)
// CustomInput.jsx
import React from "react"
export default class CustomInput extends React.Component {
constructor(props) {
super(props)
this.inputRef = React.createRef()
}
componentDidMount() {
this.inputRef.current &&
document.addEventListener("mousedown", this.handleClick)
}
componentWillUnmount() {
document.removeEventListener("mousedown", this.handleClick)
}
handleClick(e) {
console.log("clicked")
}
render() {
return (
<input type="text" ref={this.inputRef} />
)
}
}