unlayer / react-email-editor

Drag-n-Drop Email Editor Component for React.js
https://unlayer.com/embed
MIT License
4.53k stars 730 forks source link

Can't get it to work in NextJS #340

Closed redimongo closed 1 year ago

redimongo commented 1 year ago

Hi I am wondering if anyone is able to help. I have a NextJS app, and the following won't work

when I hit export or save I get this error

Unhandled Runtime Error
TypeError: undefined is not an object (evaluating 'emailEditorRef.current.editor.exportHtml')
Call Stack
dispatchEvent

[native code]
dispatchDiscreteEvent

[native code]
import { useRef } from "react";
import dynamic from "next/dynamic";

const EmailEditor = dynamic(() => import("react-email-editor"), {
  ssr: false,
});

export default function Email() {
  const emailEditorRef = useRef(null);

  function saveDesign() {
    emailEditorRef.current.editor.saveDesign((design) => {
      console.log("saveDesign", design);
    });
  }

  function exportHtml() {
    emailEditorRef.current.editor.exportHtml((data) => {
      const { design, html } = data;
      console.log("exportHtml", html);
    });
  }

  function onLoad() {
    // editor instance is created
    // you can load your template here;
    const templateJson = {};
    emailEditorRef?.current?.editor?.loadDesign(templateJson);
  }

  function onReady() {
    // editor is ready
    console.log("onReady");
  }

  return (
    <div className="">
      <div>
        <button onClick={saveDesign}>Save Design</button>
        <button onClick={exportHtml}>Export HTML</button>
      </div>

      <div className="h-screen overflow-hidden">
        <EmailEditor
          ref={emailEditorRef}
          onLoad={onLoad}
          onReady={onReady}
          // works for now, the second email builder gets hidden.
          // minHeight="100vh"
        />
      </div>
    </div>
  );
}
redimongo commented 1 year ago

After hours of attempts I have it working for everyone else here is the code note you need to make it a component first

You also need the import { EditorRef } from '@/libraries/editor/typs'; which is this file https://github.com/unlayer/react-email-editor/blob/master/src/types.ts

/component/mail/email.tsx

import React, { useRef, useState } from 'react';
import dynamic from 'next/dynamic';
import { EditorRef } from '@/libraries/editor/typs';
import sample from '../../../libraries/unlayer.json';
import EmailEditor from 'react-email-editor';

const EmailEditorPage: React.FC = () => {
  const emailEditorRef = useRef<EditorRef | null>(null);
  const [preview, setPreview] = useState(false);

  const exportHtml = () => {
    emailEditorRef.current?.editor?.exportHtml((data) => {
      const { design, html } = data;
      console.log('exportHtml', html);
      alert('Output HTML has been logged in your developer console.');
    });
  };

  const togglePreview = () => {
    if (preview) {
      emailEditorRef.current?.editor?.hidePreview();
      setPreview(false);
    } else {
      emailEditorRef.current?.editor?.showPreview('desktop');
      setPreview(true);
    }
  };

  const onDesignLoad = (data) => {
    console.log('onDesignLoad', data);
  };

  const onLoad = () => {
    console.log('onLoad');
    alert("loading")
    emailEditorRef.current?.editor?.addEventListener(
      'design:loaded',
      onDesignLoad
    );

    emailEditorRef.current?.editor?.loadDesign(sample);
  };

  const onReady = () => {
    console.log('onReady');
  };

  return (
    <div>
      <div>
        <button onClick={exportHtml} id="export-button">Export HTML</button>
      </div>
      <React.StrictMode>
      <EmailEditor
        ref={emailEditorRef}
        onLoad={onLoad}
        onReady={onReady}
      />
      </React.StrictMode>
    </div>
  );
};

export default EmailEditorPage;

I hope this helps people

To use it in a page

import EmailEditorPage from "@/components/dashboard/marketing/emailmarketing";

const EmailEditor: React.FC = () => {
  return <EmailEditorPage />;
};

export default EmailEditor;
xcaeser commented 1 year ago

I didn't have to do all that in nextjs 13.4.12 lol here's my code:

"use client";
import { INewsletter } from "@/types";
import EmailEditor from "react-email-editor";
import { useRef } from "react";

interface IProps {
  newsletter: INewsletter | undefined;
}

const EditorView = ({ newsletter }: IProps) => {
  const emailEditorRef = useRef<any>(null);

  const onReady = () => {
    const templateJson = newsletter?.newsletterJson; // Extract the data from the response
    // console.log("templateJson", templateJson);

    emailEditorRef.current.editor.loadDesign(templateJson);
  };

  return (
    <div className="py-1 px-3 flex flex-col">
        <EmailEditor
          ref={emailEditorRef}
          onReady={onReady}
          locale="fr-FR"
          style={{
            height: "calc(100vh - 130px)",
            width: "calc(100vh - 130px)",
          }}
        />
    </div>
  );
};

export default EditorView;