javascript - 在单页中使用具有多个 Draft.js 编辑器的高阶组件

标签 javascript reactjs draftjs draft-js-plugins

我正在开发一个主页,该主页由八个不同的组件组成,代表页面内容的各个方面。我希望使用使用 Draft.js 的自定义构建的 InlineEditor 组件来编辑其中三个。当我最初尝试执行此操作时,第二个和第三个组件的编辑工具栏仅适用于第一个组件。所以这是一个 Draft.js 问题。通过创建三个独立的 InlineEditor 组件,然后在必要时单独使用每个组件,我能够让一切正常工作,但这似乎是多余的。

我认为必须有一种更好的方法来使用 HOC 或 render props 来做到这一点,但我很难正确设置它。关于什么可能是更好的方法来解决这个问题有什么想法吗?

这是初始的 InlineEditor 组件:

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { EditorState, convertFromRaw } from 'draft-js'
import Editor from 'draft-js-plugins-editor'
import createUndoPlugin from 'draft-js-undo-plugin'
import createToolbarPlugin, { Separator } from 'draft-js-static-toolbar-plugin'
import createToolbarLinkPlugin from 'draft-js-toolbar-link-plugin'
import {
  ItalicButton,
  BoldButton,
  UnderlineButton,
  CodeButton,
  HeadlineOneButton,
  HeadlineTwoButton,
  HeadlineThreeButton,
  UnorderedListButton,
  OrderedListButton,
  BlockquoteButton,
  CodeBlockButton
} from 'draft-js-buttons'
import { Flex, Box } from 'rebass'
import FontAwesome from 'react-fontawesome'
import {
  ToolbarNav,
  EditPanel,
  StaticToolbar,
  TextInfo,
  DefaultButton,
  SuccessButton,
  InlineLink
} from 'styles'

// Set up Draft.js toolbar and plugins
const undoPlugin = createUndoPlugin()
const toolbarLinkPlugin = createToolbarLinkPlugin({
  inputPlaceholder: 'Insert URL here...'
})
const { LinkButton } = toolbarLinkPlugin
const { UndoButton, RedoButton } = undoPlugin
const toolbarPlugin = createToolbarPlugin({
  structure: [
    BoldButton,
    ItalicButton,
    UnderlineButton,
    CodeButton,
    Separator,
    HeadlineOneButton,
    HeadlineTwoButton,
    HeadlineThreeButton,
    Separator,
    UnorderedListButton,
    OrderedListButton,
    BlockquoteButton,
    CodeBlockButton,
    LinkButton,
    Separator,
    UndoButton,
    RedoButton
  ]
})
const { Toolbar } = toolbarPlugin
const plugins = [toolbarPlugin, toolbarLinkPlugin, undoPlugin]

class InlineEditor extends Component {
  displayName = 'inline editor component'
  constructor(props) {
    super(props)

    this.state = {
      editorState: EditorState.createWithContent(
        convertFromRaw(this.props.rawContent)
      ),
      showURLInput: false,
      urlValue: '',
      readOnly: true
    }
  }
  onChange = editorState => this.setState({ editorState })
  focus = () => this.refs.editor.focus()
  onEdit = e => {
    e.preventDefault()
    this.setState({
      readOnly: false
    })
  }
  onSave = () => {
    // save new content
    this.setState({
      showURLInput: false,
      urlValue: '',
      readOnly: true
    })
  }
  onCancel = () => {
    // cancel editing
    this.setState({
      editorState: EditorState.createWithContent(
        convertFromRaw(this.props.rawContent),
        this.decorator
      ),
      showURLInput: false,
      urlValue: '',
      readOnly: true
    })
  }
  renderToolbar = () => {
    return (
      <ToolbarNav>
        <StaticToolbar>
          <Toolbar />
        </StaticToolbar>
      </ToolbarNav>
    )
  }
  render() {
    const { editorState, readOnly } = this.state
    const { auth } = this.props
    return (
      <EditPanel>
        <Flex wrap>
          <Box w={'90%'}>{!readOnly && this.renderToolbar()}</Box>
          <Box mt={1}>
            <Editor
              editorState={editorState}
              onChange={this.onChange}
              plugins={plugins}
              ref="{(element) => { this.editor = element }}"
              readOnly={readOnly}
            />
            {auth.isAuthenticated &&
              readOnly && (
                <TextInfo>
                  <InlineLink onClick={this.onEdit} title="Edit">
                    <FontAwesome name="pencil" /> Edit
                  </InlineLink>
                </TextInfo>
              )}
          </Box>
          <Box width={'40%'} mr={1} mt={1}>
            {!readOnly && (
              <DefaultButton
                className={`block`}
                type="button"
                onClick={this.onCancel}>
                Cancel
              </DefaultButton>
            )}
          </Box>
          <Box width={'40%'} mt={1}>
            {!readOnly && (
              <SuccessButton
                className={`block`}
                type="button"
                onClick={this.onSave}>
                Save
              </SuccessButton>
            )}
          </Box>
        </Flex>
      </EditPanel>
    )
  }
}

const mapStateToProps = state => {
  return {
    auth: state.auth
  }
}

export default connect(mapStateToProps)(InlineEditor)

目前,这是由 About 等组件访问的,如下所示:

return (
    <InlineEditor
    auth={ this.props.auth }
    rawContent={ about }/>
)

最佳答案

我能够通过创建一个 InlineEditor 组件来解决这个问题,该组件在其构造函数内部传递工具栏插件,即

constructor(props) {
    super(props)

    this.undoPlugin = createUndoPlugin()

    this.toolbarLinkPlugin = createToolbarLinkPlugin({
       inputPlaceholder: "Insert URL here...",
    })

    // etc...
}

关于javascript - 在单页中使用具有多个 Draft.js 编辑器的高阶组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48549391/

相关文章:

javascript - mouseover 和 mouseenter 事件有什么区别?

javascript - 如何在每次渲染之前重置 UseEffect React Hooks 中的数据?

reactjs - 如何在 python 中使用 selenium webdriver 将内容设置到 mui-rte 中?

javascript - 如何合并多个draft-js ContentState

javascript - 增加 React 中的超时时间 - neo4j 应用程序

javascript - 检测模糊,也就是失去 Draft.js 编辑器的焦点

javascript - 将 UTC 时间字符串转换为用户本地时间

javascript - 如何加载 window.open ('url' ) once only PHP & JQuery

javascript - 切换下一个表

reactjs - 如何在 VS Code 中调试 React?错误断点已设置但尚未绑定(bind)