【问题标题】:How to Access EditorState from Decorated Component如何从装饰组件访问 EditorState
【发布时间】:2019-03-06 15:43:50
【问题描述】:

我开始使用 Draft-js 中的装饰器,并且能够渲染在 CompositeDecorator 中定义的组件。记录在案的行为效果很好。

也就是说,我正试图弄清楚如何从这些组件中访问 editorState。 contentState 是传入的唯一有用的道具,但据我所知,我无法从 contentState 解析 editorState。

我主要尝试做的是能够通过与呈现的组件本身交互来编辑或删除。即打开一个对话框来更改实体数据。在 dialogForm 的 onSave() 中,我需要推送新的 editorState,但到目前为止,它不在范围内。

有没有办法在装饰器组件的范围内访问 editorState 或者有更智能的解决方案?

【问题讨论】:

  • 请在需要澄清或解决的地方分享代码。理论上的解释是不够的。

标签: reactjs draftjs


【解决方案1】:

你可以尝试设置一个新的装饰器:https://draftjs.org/docs/advanced-topics-decorators/#setting-new-decorators

getDecorators = (props) => {
    return compositeDecorators([
      {
        strategy: YourDecoratorStrategy,
        component: YourDecoratorComponent,
        props: {
          // your props here
        },
      },
    ]);
  };
const { editorState } = this.state;
const forcedState = EditorState.set(editorState, { decorator: this.getDecorators(this.props) });
this.setState({ editorState: forcedState });

【讨论】:

    【解决方案2】:

    在使用装饰器创建 EditorState 时,您可以使用工厂方法,即不要编写如下内容:

    const compositeDecorator = new CompositeDecorator([
        {
            strategy,
            component: DecoratedComponent,
        }  
    ])
    
    class YourSuperEditor {
        state = {
            editorState: createWithContent(initialValue, compositeDecorator),
        }
        ...
        render = () => <Editor ... />
    }
    

    你可以这样做:

    const compositeDecorator = getters => new CompositeDecorator([
        {
            strategy,
            component: DecoratedComponent,
            props: ...getters,
        }  
    ])
    
    class YourSuperEditor {
        state = {
            editorState: createWithContent(
                initialValue,
                compositeDecorator({
                    getState: () => this.state,
                    getInitialValueFromProps: () => this.props.value,
                })
            ),
        }
        ...
        render = () => <Editor ... />
    }
    

    附:仅当 EditorState 发生更改时,装饰组件才会重新渲染,因此如果您想根据 EditorState 之外的状态/道具重新渲染它们,您需要通过执行 @987654327 来触发编辑器的重新渲染@ — 这很丑陋,但在解决 this issue 之前我们无能为力。

    【讨论】:

      【解决方案3】:

      所以我刚刚遇到了这个问题并使用装饰器属性解决了它。

      {
        strategy: handleSentenceStrategy,
        component: SentenceComponent,
        props: {
          setSentenceFocus,
        },
      },
      

      setSentenceFocus 只是创建编辑器的任何反应回调挂钩(或静态函数)。

      主要问题是每当道具发生变化时,它都会重新渲染组件(这是正确的),因此如果您传入编辑器状态,您的性能(和视觉渲染)就会出现问题。

      我通过略显老套的 useRef 方法解决了这个问题。

        const editorStateRef = useRef<EditorState>(editorState)
        editorStateRef.current = editorState
        const updateSentenceFocus = useCallback((focusedSentence: string) => {
          const editorState = editorStateRef.current
          const newEditorState = doSomething()
          setEditorState(newEditorState)
        }, [])
      

      这里的重点是回调本身永远不会改变,并且使用静态 ref 引用。这使它更加优化。

      如果您在击键时执行操作,这可能(很可能会)导致渲染顺序方面的问题,但它适用于我的用例。如果您做的不仅仅是一个小调整,我建议您使用 blockRendererFn,它可以为您提供最大的灵活性(具有更多的复杂性权衡)。

      反之亦然(尽管我不建议亲自更新装饰器中的 editorState)。

      {
        strategy: handleSentenceStrategy,
        component: SentenceComponent,
        props: {
          getEditorState,
        },
      },
      
      const getEditorState = useCallback((): EditorState => {
            return editorStateRef.current
      }, [])
      

      希望这是有道理的!

      【讨论】:

        【解决方案4】:

        我没有明确的答案(尽管这似乎是一个好问题!)但我正在研究 DraftJs 示例,TexEditor example 似乎很有用(如果您还没有咨询过) .它使用自定义块,然后传入处理更新编辑器状态以响应块组件更改的道具。

        如果您找到解决方案,请告诉我,我想知道您最后是如何解决的。

        编辑:我知道您引用了 CompositeDecorator,但找不到您所描述的示例

        【讨论】:

        • 这帮助很大。谢谢你指出这一点。我忽略了那个例子,认为它在某种程度上是 LaTex 特定的。我将尝试将代码笔与一个简化的示例放在一起。具体说明在 blockRenderFn 上定义回调有点复杂。
        • @BlaineGarrett 嘿,你找到解决方案了吗?我也在努力解决类似的问题。我目前正在使用上下文来解决它,但感觉很奇怪,所以我想共享道具或 editorState 的方式是合适的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-11-27
        • 2011-10-30
        • 1970-01-01
        • 2018-11-26
        • 2021-02-07
        • 1970-01-01
        • 2014-07-18
        相关资源
        最近更新 更多