[英]React useRef() not getting defined
I have a prosemirror based editor that I'd like to enable real-time collaboration on.我有一个基于 prosemirror 的编辑器,我想启用实时协作。 So I've set up a socket server as described here
所以我设置了一个套接字服务器,如此处所述
I set up the WebsocketProvider
as a useRef()
so that we're not constantly re-creating it everytime we render the component (before I was spinning up dozens of websockets).我将
WebsocketProvider
设置为useRef()
,这样我们就不会在每次渲染组件时都不断地重新创建它(在我启动数十个 websocket 之前)。 However, now it's not even getting defined, as the console.log(this.yXmlFragment, this.provider)
in get plugins()
is returning both as undefined
但是,现在它甚至没有被定义,因为
get plugins()
中的console.log(this.yXmlFragment, this.provider)
将两者都返回为undefined
My desired behavior is that I want provider
and yXmlFragment
to be updated only when the sectionID
changes, not for any other re-render.我想要的行为是我希望
provider
和yXmlFragment
仅在sectionID
更改时更新,而不是任何其他重新渲染。 But it's not even being set the first time.但它甚至不是第一次设置。 Can anyone explain how I'm wrong?
谁能解释我错了?
import React, { useContext, useEffect, useRef } from "react";
import Editor, { Extension } from "rich-markdown-editor";
import * as Y from 'yjs';
import { WebsocketProvider } from 'y-websocket';
import { ySyncPlugin, yCursorPlugin } from 'y-prosemirror';
import { AuthUserContext } from "../Util/AuthUser";
type EditorInput = {
id?: string;
readOnly?: boolean;
defaultValue?: string;
value?: string;
placeholder?: string;
sectionID?: string;
onChange(e: string): void;
};
const EditorContainer: React.FC<EditorInput> = (props) => {
const {
id,
readOnly,
placeholder,
sectionID,
defaultValue,
value,
onChange,
} = props;
const { currentUser } = useContext(AuthUserContext);
const provider = useRef<WebsocketProvider>();
const yXmlFragment = useRef<Y.XmlFragment>();
useEffect(() => {
const ydoc = new Y.Doc();
yXmlFragment.current = ydoc.getXmlFragment('prosemirror');
provider.current = new WebsocketProvider('wss://my_socket_server.herokuapp.com', `${sectionID}`, ydoc);
}, [sectionID]);
return (
<div className="Editor-Container" id={id}>
<Editor
onChange={(e: any) => onChange(e)}
defaultValue={defaultValue}
value={value}
readOnly={readOnly}
placeholder={placeholder}
extensions={[
new yWebsocketExt(provider.current, yXmlFragment.current, currentUser)
]}
/>
</div>
);
};
export default EditorContainer;
class yWebsocketExt extends Extension {
provider?: WebsocketProvider;
yXmlFragment?: Y.XmlFragment;
currentUser: User;
constructor(provider: WebsocketProvider | undefined, yXmlFragment: Y.XmlFragment | undefined, currentUser: User) {
super();
if (provider?.shouldConnect) {
provider?.connect()
} else {
provider?.disconnect()
}
this.provider = provider;
this.yXmlFragment = yXmlFragment;
this.currentUser = currentUser;
}
get name() {
return "y-websocket sync";
}
get plugins() {
console.log(this.yXmlFragment, this.provider);
if (this.yXmlFragment && this.provider) {
this.provider.awareness.setLocalStateField('user', {
name: currentUser.name,
color: '#1be7ff',
});
return [
ySyncPlugin(this.yXmlFragment),
yCursorPlugin(this.provider.awareness),
]
}
return []
}
};
This is happening because you are including sectionID
in the dependency list of the useEffect
within EditorContainer
.发生这种情况是因为您将
sectionID
包含在EditorContainer
内useEffect
的依赖项列表中。 Because sectionID
doesn't change on initial load, this useEffect
never fires.因为
sectionID
在初始加载时不会改变,所以这个useEffect
永远不会触发。 I've created a minimal example of this here:https://codesandbox.io/s/focused-babbage-ilx4j?file=/src/App.js我在这里创建了一个最小的例子:https://codesandbox.io/s/focused-babbage-ilx4j?file=/src/App.js
I recommend changing useEffect
to useMemo
because it runs at least once on initial render of EditorContainer
.我建议将
useEffect
更改为useMemo
,因为它在EditorContainer
的初始渲染时至少运行一次。 And you still get the performance benefit because it shouldn't rerun unless sectionID
changes.而且您仍然可以获得性能优势,因为除非
sectionID
更改,否则它不应重新运行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.