`forwardRef` error when dynamically importing a module in Next.js

Viewed 3025

I'm trying to use forwardRef on an external component but ref.current is not the actual ref. Not sure if I'm missing something.

I'm doing:

const Editor = dynamic(() => import("react-markdown-editor-lite"), {
  ssr: false
});

const ForwardedRefEditor = forwardRef((props, ref) => (
  <Editor {...props} ref={ref} />
));

-----

const editorRef = useRef(null);
<ForwardedRefEditor
  ref={editorRef}
  value={content}
  onChange={({ text }) => setContent(text)}
/>

Full code: https://codesandbox.io/s/objective-benz-qh4ec?file=/pages/index.js:63-73

More info: https://github.com/vercel/next.js/issues/4957

1 Answers

You need to wrap your component in a custom component.

Using forwardRef:

Wrap your Editor component:

import React from "react";
import Editor from "react-markdown-editor-lite";

export default function WrappedEditor({ editorRef, ...props }) {
  return <Editor {...props} ref={editorRef} />;
}

And then import it dynamically:

import dynamic from "next/dynamic";
import { useRef, useState, forwardRef } from "react";

const Editor = dynamic(() => import("../WrappedEditor"), {
  ssr: false
});

const ForwardRefEditor = forwardRef((props, ref) => 
  <Editor {...props} editorRef={ref}/>
)

export default function IndexPage() {
  const editorRef = useRef(null);
  const [content, setContent] = useState("");

  console.log("editorRef", editorRef.current);

  return (
    <ForwardRefEditor
      ref={editorRef}
      value={content}
      onChange={({ text }) => setContent(text)}
    />
  );
}

CodeSandbox

You can also use the custom prop approach without using forwardRef.

Custom prop

Wrap your Editor component exactly as in the previous example:

import React from "react";
import Editor from "react-markdown-editor-lite";

export default function WrappedEditor({ editorRef, ...props }) {
  return <Editor {...props} ref={editorRef} />;
}

Pass the custom ref prop to the Editor component:

import dynamic from "next/dynamic";
import { useRef, useState } from "react";

const Editor = dynamic(() => import("../WrappedEditor"), {
  ssr: false
});

export default function IndexPage() {
  const editorRef = useRef(null);
  const [content, setContent] = useState("");

  console.log("editorRef", editorRef.current);

  return (
    <Editor
      editorRef={editorRef}
      value={content}
      onChange={({ text }) => setContent(text)}
    />
  );
}

CodeSandbox

Related