jasonphillips / draft-js-richbuttons-plugin

A plugin for adding rich formatting controls - https://jasonphillips.github.io/draft-js-richbuttons-plugin/
38 stars 14 forks source link

Content is displayed in the second editor when using rich buttons #9

Closed dadtmt closed 7 years ago

dadtmt commented 7 years ago

Hello, I have an editor with rich buttons wrapped in a RichTextEditor component. When I render two RichTextEditor I have this behavior: when selecting text in the first editor and clicking on a rich button the content with styles is rendered in the second. Here is an example : https://dadtmt.github.io/two-editors/ Here a repo to quiclkly reproduce the issue: https://github.com/dadtmt/two-editors

The RichTextEditor code :

import React, { Component } from 'react'
import Editor from 'draft-js-plugins-editor'
import createRichButtonsPlugin from 'draft-js-richbuttons-plugin'
import { EditorState } from 'draft-js'

const richButtonsPlugin = createRichButtonsPlugin()
const { BoldButton, H1Button } = richButtonsPlugin

const plugins = [richButtonsPlugin]

export default class RichTextEditor extends Component {

  constructor() {
    super()
    this.handleChange = this.handleChange.bind(this)
    this.state = { editorState: EditorState.createEmpty() }
  }

  handleChange(editorState) {
    this.setState({ editorState })
  }

  render() {

    return (
      <div style={{
        border: '1px black solid',
        textAlign: 'left',
        margin: '20px 25%',
        padding: '10px 10px'
      }}>
          <BoldButton />
          <H1Button />
          <p />
          <Editor
            editorState={this.state.editorState}
            onChange={this.handleChange}
            plugins={plugins}
          />
      </div>
    )
  }
}
jasonphillips commented 7 years ago

Good point (and helpful example). For some reason, the authors of draft-js-plugins have always structured their examples the way I did in this repository, where the plugins are instantiated above the component. But that will not work when you create multiple editors at the same time on the page, because the plugin (and everything outside the closure of the Component itself) will then be a single object shared across all instances.

However, by changing up the syntax a bit, you can make your component safe for multiple copies. I created a PR on your example to illustrate the syntax:

https://github.com/dadtmt/two-editors/pull/1

I should probably update the docs and examples of this repository to follow that approach, in case more than one editor is created. So far I have adhered more or less to the style of the draft-js-plugins examples, but those end up running into this problem.

See also: https://github.com/draft-js-plugins/draft-js-plugins/issues/548

jasonphillips commented 7 years ago

And I'll go ahead and show the corrected code here to help others who might run into this:

import React, { Component } from 'react'
import Editor from 'draft-js-plugins-editor'
import createRichButtonsPlugin from 'draft-js-richbuttons-plugin'
import { EditorState } from 'draft-js'

export default class RichTextEditor extends Component {

  constructor() {
    super()
    // instantiate plugins, plugin components on the component instance
    const richButtonsPlugin = createRichButtonsPlugin()
    const { BoldButton, H1Button } = richButtonsPlugin
    this.plugins = [richButtonsPlugin]
    this.components = { BoldButton, H1Button }

    this.handleChange = this.handleChange.bind(this)
    this.state = { editorState: EditorState.createEmpty() }
  }

  handleChange(editorState) {
    this.setState({ editorState })
  }

  render() {
    const { BoldButton, H1Button } = this.components;

    return (
      <div style={{
        border: '1px black solid',
        textAlign: 'left',
        margin: '20px 25%',
        padding: '10px 10px'
      }}>
          <BoldButton />
          <H1Button />
          <p />
          <Editor
            editorState={this.state.editorState}
            onChange={this.handleChange}
            plugins={this.plugins}
          />
      </div>
    )
  }
}