简体   繁体   English

React useRef() 没有被定义

[英]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.我想要的行为是我希望provideryXmlFragment仅在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包含在EditorContaineruseEffect的依赖项列表中。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM