Мне нужно добавить несколько обработчиков событий, которые взаимодействуют с объектом вне React (например, Google Maps). Внутри этой функции-обработчика я хочу получить доступ к некоторому состоянию, которое я могу отправить этому внешнему объекту.
Если я передаю состояние как зависимость от эффекта, оно работает (я могу правильно получить доступ к состоянию) но обработчик добавления / удаления добавляется каждый раз при изменении состояния.
Если я не передаю состояние в качестве зависимости, обработчик добавления / удаления добавляется соответствующее количество раз ( по сути один раз), но состояние никогда не обновляется (или, точнее, обработчик не может получить последнее состояние).
Пример Codepen:
Возможно, лучше всего объяснить с помощью Codepen: https://codepen.io/cjke/pen/dyMbMYr?editors=0010
const App = () => {
const [n, setN] = React.useState(0);
React.useEffect(() => {
const os = document.getElementById('outside-react')
const handleMouseOver = () => {
// I know innerHTML isn't "react" - this is an example of interacting with an element outside of React
os.innerHTML = `N=${n}`
}
console.log('Add handler')
os.addEventListener('mouseover', handleMouseOver)
return () => {
console.log('Remove handler')
os.removeEventListener('mouseover', handleMouseOver)
}
}, []) // <-- I can change this to [n] and `n` can be accessed, but add/remove keeps getting invoked
return (
<div>
<button onClick={() => setN(n + 1)}>+</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
Сводка
Если список dep для эффекта равен [n]
, состояние обновляется, но добавление / удаление обработчика добавляется / удаляется для каждого изменение состояния. Если список dep для эффекта равен []
, обработчик добавления / удаления работает отлично, но состояние всегда равно 0 (начальное состояние).
Мне нужно сочетание обоих. Доступ к состоянию, но только к useEffect один раз (как если бы зависимость была []
).
Изменить: дополнительные пояснения
Я знаю, как решить эту проблему с помощью методов жизненного цикла, но не уверен, как это может работать с хуками.
Если бы это был компонент класса, он бы выглядит так:
class App extends React.Component {
constructor(props) {
super(props)
this.state = { n: 0 };
}
handleMouseOver = () => {
const os = document.getElementById("outside-react");
os.innerHTML = `N=${this.state.n}`;
};
componentDidMount() {
console.log("Add handler");
const os = document.getElementById("outside-react");
os.addEventListener("mouseover", this.handleMouseOver);
}
componentWillUnmount() {
console.log("Remove handler");
const os = document.getElementById("outside-react");
os.removeEventListener("mouseover", handleMouseOver);
}
render() {
const { n } = this.state;
return (
<div>
<strong>Info:</strong> Click button to update N in state, then hover the
orange box. Open the console to see how frequently the handler is
added/removed
<br />
<button onClick={() => this.setState({ n: n + 1 })}>+</button>
<br />
state inside react: {n}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
Обратите внимание на то, что обработчик добавления / удаления добавляется только один раз (очевидно, игнорируя тот факт, что компонент приложения не размонтирован), несмотря на изменение состояния.
I Я ищу способ повторить это с помощью крючков