side effects of onLoad implementation
The passed wrapper prop onLoad function gets called in direct response (synchronous) to the onLoad callback of the script being loaded. This does not always guarantee that the underlying component is already loaded by then.
For example the editor can be in specific route of a react application, and load the unlayer script the first time the user gets there. If the user then navigates away from that route and comes back, the script will be loaded from the cache, therefore immediately kicking in the onLoad callback.
In the demo, the onLoad function will execute this.editor.loadDesign(sample) and in my particular case add event listeners. It then blows up saying this.editor is undefined.
@HyperMaxime can you share a functional code sample of your particular scenario? If not, then any snippets would help too.
@umairsiddique I also get the same issue from time to time.
My onLoad function:
onLoad = () => {
this.editor.loadDesign(this.props.firm_prefs[1].email_templates[this.state.selectedTemplate]);
this.editor.setMergeTags([ {name: "First Name", value: "{*|first_name|*}"}, {name: "Last Name", value: "{*|last_name|*}"}, {name: "Invite Link", value: "{*|invite_link|*}"}]);
}
Where I use the onLoad:
<EmailEditor
onLoad={this.onLoad}
ref={editor => this.editor = editor}
/>
</div>
Error it spits out:

@umairsiddique I created a CodeSandbox that illustrates the issue: https://codesandbox.io/s/5kz6nzjq9p
By showing and hiding the editor, you'll see in the log that the editor is undefined when the onLoad callback function executes.
Also notice that sometimes it is actually available at the start, depending on the browser having cached the unlayer script.
@umairsiddique @HyperMaxime sorry to be a pest, but did either of you ever find a solution or work around to this issue?
Cheers.
@stroypet until we get a better solution/fix we are just pointing to the global variable unlayer.
@coxom Thanks for the reply, don't suppose I could bother you for a code snippet of what that looks like? My .js skills aren't the greatest :).
@stroypet The usage example would become something like this:
import React, { Component } from 'react'
import { render } from 'react-dom'
import EmailEditor from 'react-email-editor'
class App extends Component {
render() {
return <div>
<h1>react-email-editor Demo</h1>
<div>
<button onClick={this.exportHtml}>Export HTML</button>
</div>
<EmailEditor />
</div>
}
exportHtml = () => {
unlayer.exportHtml(data => {
const { design, html } = data
console.log('exportHtml', html)
})
}
}
render(<App />, document.getElementById('app'))
Solution with the global variable works. Just use window.unlayer. Was trying to fix it half a day, thank you all. It is not good to use global variables in React but who cares, IT WORKS! ))
The key fix is to check if this.editor && window.unlayer != undefined and by conditionally setting the onLoad prop. In my particular use case, I am using react-router-dom and an api call that Redux dispatches when the componentDidMount. I figured out this fix (fyi this.props.match is a prop passed in from react-router-dom so ignore it if your component is not using it):
// Function outside render but inside class MyClassName extends Component { }
loadDesign = design => this.editor.loadDesign(design)
render() {
// Check if Redux updated the state from mapStateToProps
const design = this.state.HtmlDocument.hasOwnProperty('design') ? JSON.parse(this.state.HtmlDocument.design) : null
// True if there are paramaters in the url, redux updated the state, and if the editor has loaded into memory
const isEditingDesign = this.props.match && design && this.editor && window.unlayer
return (
<EmailEditor minHeight="85vh" ref={editor => this.editor = editor} style={styles} onLoad={isEditingDesign ? this.loadDesign(design) : null}/>
)
}
export default withRouter(reduxConnect(mapStateToProps, mapDispatchToProps)(MyClassName))
If anyone needs additional clarity, please respond to this comment. I am willing to share more code.
@strap8, I did not test your code in practise so I might be wrong, but at first sight I think your solution misses the point of this issue. Under certain conditions, this.editor will not yet be available when the onLoad callback gets called, therefore throwing an exception if any method of it is being executed. Your solution simply doesn't run any callback in that scenario, which will indeed not throw any exception, but will also eventually not run code that is expected to run at the moment the editor is loaded.
I'm using a workaround to fix this. I facing this problem when the route change, using react-router-dom.
So, to "solve" this, I'm using 2 flags: isEditorLoaded and isComponentMounted
Initiate them in the constructor:
constructor(props) { super(props); this.editor = null; this.isEditorLoaded = false; this.isComponentMounted = false; }
Implement the hook:
componentDidMount() { this.isComponentMounted = true; this.loadTemplate(); }
Implement the onLoad:
onLoad = () => { this.isEditorLoaded = true; this.loadTemplate(); }
Then a function to be called and check if we are able to use the editor:
loadTemplate = () => { if (!this.isEditorLoaded || !this.isComponentMounted) return; this.editor.loadDesign(this.state.jsonTemplate) }
The render:
<EmailEditor ref={editor => this.editor = editor} onLoad={this.onLoad} />
I hope this can help.
This solution works for me https://github.com/unlayer/react-email-editor/issues/7#issuecomment-348227970
@mvcarvalho This worked for me when trying to use setMergeTags. It feels like the best workaround so far. Have you managed to get it working in a different way since your post?
@mvcarvalho Works for me, thank you!
in case it helps anyone, I have posted up a working solution at https://github.com/unlayer/react-email-editor/issues/100#issuecomment-644694574
Sometimes the email editor shows up but most of the time on refreshing/reconnecting I get these errors in the browser console. The same thing happens in the case of "save Design" and "load design" both
- ERROR: (Cannot read property save Design/ load Design of Undefined)
- ERROR: (Prop
iddid not match. Server: "editor-2" Client: "editor-1")
sometimes even with ERROR2 things work fine.
WHAT SHOULD I DO......?

