TinyMCE - Problem with Initialisation in React?

1k Views Asked by At

I'm trying to initialise TinyMCE, and have written it as a React Component. Using the code below, the editor renders, but after 10 seconds displays the following error:

tinymce can only be initialised when in a document
    at Editor._this.initialise (http://localhost:4052/bundle.js:89548:27)
    at http://localhost:4052/bundle.js:89544:59

Using the npm package `@tinymce/tinymce-react', and following the setup guide, I've produced the following component:

import React, { useEffect, useRef, useState } from 'react'
import { Editor } from '@tinymce/tinymce-react'
import { Box, Button } from '@mui/material'

const TinyMCE = ({ initialValue, onSubmit }) => {
  const [loaded, setLoaded] = useState(false)
  const [value, setValue] = useState(initialValue ?? '<p></p>')
  useEffect(() => {
    setLoaded(true)
  }, [])
  const editorRef = useRef(null)

  const handleChange = (e) => setValue(e.content)

  const handleSubmit = () => console.log(value)

  return (
    <Box>
      <Box id="tinymceeditor" />
      <Editor
        value={value}
        onEditorChange={handleChange}
        apiKey="*****"
        init={{
          selector: 'tinymceeditor',
          plugins: 'advlist code emoticons link lists table',
          toolbar: 'bold italic | bullist numlist | link emoticons',
          height: 300
        }}
      />
      <Button variant="contained" color="primary" onClick={handleSubmit}>
        Submit
      </Button>
    </Box>
  )
}

export default TinyMCE

The npm package throws the error after 10 seconds, from here:

        _this.initialise = function (attempts) {
            var _a, _b, _c;
            if (attempts === void 0) { attempts = 0; }
            var target = _this.elementRef.current;
            if (!target) {
                return; // Editor has been unmounted
            }
            if (!(0, Utils_1.isInDoc)(target)) {
                // this is probably someone trying to help by rendering us offscreen
                // but we can't do that because the editor iframe must be in the document
                // in order to have state
                if (attempts === 0) {
                    // we probably just need to wait for the current events to be processed
                    setTimeout(function () { return _this.initialise(1); }, 1);
                }
                else if (attempts < 100) {
                    // wait for ten seconds, polling every tenth of a second
                    setTimeout(function () { return _this.initialise(attempts + 1); }, 100);
                }
                else {
                    // give up, at this point it seems that more polling is unlikely to help
                    throw new Error('tinymce can only be initialised when in a document');
                }
                return;
            }

Whilst I cannot find any examples of the exact same error, I assume it's something to do with the initialisation. I've tried rendering the component only after the parent component mounted.

The Editor component accepts an oninit parameter. I've tried using this to update the ref onInit={(evt, editor) => (editorRef.current = editor)} but this does not affect the error being thrown.

One forum suggested it was webpack, so I included the MiniCssExtractPlugin as per their suggestion there. Here is my webpack config:

module.exports = {
    entry: {
        app: './src/index.js'
    },
    module: {
        rules: [
            {
                test: /\.(ts|js|jsx)x?$/,
                exclude: /(node_modules|bower_components)/,
                loader: 'babel-loader',
                options: {
                    presets: ['@babel/env']
                }
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
            {
                test: /\.(png|jpe?g|gif)$/i,
                use: ['file-loader']
            }
        ]
    },
    resolve: {
        extensions: ['*', '.js', '.jsx']
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
        clean: true
    },
    plugins: [
        new Dotenv(),
        new HtmlWebpackPlugin({
            template: './src/assets/index.html',
            favicon: './src/assets/images/icons/favicons/favicon.ico',
            meta: {viewport: 'width=device-width, initial-scale=1'}
        }),
        new MiniCssExtractPlugin()
    ],
}

Any help would be really appreciated!

2

There are 2 best solutions below

0
GLHF On

I think I've found your problem.

You have that Box element with id=tinymceeditor, and in Editor's init you have a selector: "tinymceeditor". This may cause this bug, Editor may try to choose that element with selector value.

Change <Box id="tinymceeditor" /> to <Box id="boxId" /> and remove selector: 'tinymceeditor' in Editor's init.

0
mohsen alizadeh On

It appears that the error "tinymce can only be initialised when in a document" is occurring because you are trying to initialize TinyMCE at a stage where the React component hasn't been properly placed in the HTML document yet.

To resolve this issue, you can take the following steps:

1 - Make sure that the TinyMCE component is properly rendered within the DOM. One solution is to ensure that the element with the "tinymceeditor" id, which is used to set the selector value in TinyMCE settings, exists at the time of rendering the TinyMCE component.

2 - Ensure that all TinyMCE settings are fully loaded. It seems that you have set all the necessary settings in your code, but make sure that all the required plugins and toolbar items for TinyMCE are properly loaded.

3 - Check the loading delay of TinyMCE. In your code, you're using the setTimeout function to wait if the TinyMCE component is not present in the DOM and retry after a specified time. Make sure you provide a reasonable duration for waiting until the component is correctly rendered.

4 - Verify the compatibility between the versions of TinyMCE and React you're using. Make sure that the versions of TinyMCE and React are supported and compatible with each other in your project.

I hope this helps in resolving your issue. If you encounter any further problems or need additional guidance, please provide more of the relevant code for us to assist you better.