在单个页面中使用具有多个 Draft.js 编辑器的高阶组件
Using a higher order component with multiple Draft.js editors in single page
我正在制作一个主页,该主页由代表页面内容各个方面的八个不同组件组成。我想让其中三个可以使用使用 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
内部的工具栏插件中传递,即
constructor(props) {
super(props)
this.undoPlugin = createUndoPlugin()
this.toolbarLinkPlugin = createToolbarLinkPlugin({
inputPlaceholder: "Insert URL here...",
})
// etc...
}
我正在制作一个主页,该主页由代表页面内容各个方面的八个不同组件组成。我想让其中三个可以使用使用 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
内部的工具栏插件中传递,即
constructor(props) {
super(props)
this.undoPlugin = createUndoPlugin()
this.toolbarLinkPlugin = createToolbarLinkPlugin({
inputPlaceholder: "Insert URL here...",
})
// etc...
}