【发布时间】:2019-08-04 20:32:36
【问题描述】:
我正在尝试将事件发射器与 React useEffect 和 useState 一起使用,但它总是获取初始状态而不是更新状态。如果我直接调用事件处理程序,即使使用setTimeout,它也可以工作。
如果我将值传递给 useEffect() 第二个参数,它会使其工作,但这会导致每次值更改时重新订阅事件发射器(由击键触发)。
我做错了什么?我尝试了useState、useRef、useReducer 和useCallback,但都无法正常工作。
这是一个复制品:
import React, { useState, useEffect } from "react";
import { Controlled as CodeMirror } from "react-codemirror2";
import "codemirror/lib/codemirror.css";
import EventEmitter from "events";
let ee = new EventEmitter();
const initialValue = "initial value";
function App(props) {
const [value, setValue] = useState(initialValue);
// Should get the latest value, both after the initial server load, and whenever the Codemirror input changes.
const handleEvent = (msg, data) => {
console.info("Value in event handler: ", value);
// This line is only for demoing the problem. If we wanted to modify the DOM in this event, we would instead call some setState function and rerender in a React-friendly fashion.
document.getElementById("result").innerHTML = value;
};
// Get value from server on component creation (mocked)
useEffect(() => {
setTimeout(() => {
setValue("value from server");
}, 1000);
}, []);
// Subscribe to events on component creation
useEffect(() => {
ee.on("some_event", handleEvent);
return () => {
ee.off(handleEvent);
};
}, []);
return (
<React.Fragment>
<CodeMirror
value={value}
options={{ lineNumbers: true }}
onBeforeChange={(editor, data, newValue) => {
setValue(newValue);
}}
/>
{/* Everything below is only for demoing the problem. In reality the event would come from some other source external to this component. */}
<button
onClick={() => {
ee.emit("some_event");
}}
>
EventEmitter (doesnt work)
</button>
<div id="result" />
</React.Fragment>
);
}
export default App;
这是App2中相同的代码沙箱:
https://codesandbox.io/s/ww2v80ww4l
App 组件有 3 种不同的实现 - EventEmitter、pubsub-js 和 setTimeout。只有 setTimeout 有效。
编辑
为了阐明我的目标,我只希望 handleEvent 中的值在所有情况下都与 Codemirror 值匹配。单击任何按钮时,应显示当前的 codemirror 值。而是显示初始值。
【问题讨论】:
-
它看起来与钩子无关。
useEffect以异步方式执行。并且 handleEvent 方法直接改变 DOM 中的某些内容。因此,DOM 突变发生在您从服务器获取值之前。如果你用 React 的基于 state 值的渲染方式,就不会发生这种情况。 -
@Dinesh 在我的真实代码中,我没有在事件处理程序中修改 DOM。这只是为了演示问题。
标签: javascript reactjs codemirror eventemitter react-hooks