У меня есть элемент ввода, который отображается в зависимости от состояния.
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>
)
По сути, я хочу прослушать щелчок по документу, чтобы скрыть ввод всякий раз, когда пользователь щелкает за пределами этого элемента ввода.
Прямо сейчас я делаю это:
componentDidMount() {
document.addEventListener('mousedown', this.handleClick);
}
handleClick = event => {
//do some logic
};
Но мне было интересно, правильный ли это способ, потому что событие существует и срабатывает, даже когда элемент не отображается.
Итак, я пробовал это:
componentDidUpdate () {
const {isNameInputVisible} = this.state;
isNameInputVisible && document.addEventListener('mousedown', this.handleClick);
}
Но это не работает.
Вопрос 1: Как правильно прикреплять события к документу, когда он зависит от других условно отображаемых элементов??
Вопрос 2: Каков правильный способ прикрепления событий, например, таких как нажатие выхода, для закрытия диалогов, которые о и т.д.??
вот как я это делаю прямо сейчас :) Но обработчик срабатывает даже тогда, когда он мне не нужен, потому что Input не виден. Вот почему я задаюсь вопросом, правильный ли это путь?
Можно сделать ввод компонентом
Вам нужно добавить прослушиватель событий в метод componentDidMount
, только если ссылка на условно визуализируемый элемент существует. Вы можете узнать, была ли ссылка прикреплена к элементу, используя this.refName.current
.
Самое главное здесь то, что элемент 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.info("clicked")
}
render() {
return (
<input type = "text" ref = {this.inputRef} />
)
}
}
Так не пойдет. как по умолчанию. Ввод невидим, поэтому react не создаст на него ссылку. Я пробовал тот же подход в componentDidMount(). Вот так: componentDidMount() { this.inputRef.current && document.addEventListener()..... }, но при таком подходе, даже когда состояние было обновлено с isInputVisible до true, eventListener не был прикреплен к документу.
Это связано с тем, что ссылку необходимо прикрепить к условному элементу с помощью методов жизненного цикла компонента, которые вызываются после создания входных данных. Как только вы переместите элемент ввода в его собственный компонент с его собственными методами жизненного цикла, он отлично заработает. Я обновлю свой ответ этим.
Добавьте прослушиватель в componentDidmount. Проверьте
target
в обработчике. Обязательно удалите слушателя вcomponentWillUnmount