Как получить доступ к EditorState из декорированного компонента

Я начинаю работать с декораторами в draft-js и могу отображать свои компоненты, определенные в CompositeDecorator. Документированное поведение прекрасно работает.

Тем не менее, я пытаюсь выяснить, как я могу получить доступ к editorState из этих компонентов. ContentState - единственная полезная пропущенная информация, но, насколько я могу судить, я не могу разрешить editorState из contentState.

В первую очередь я пытаюсь редактировать или удалять, взаимодействуя с самим отображаемым компонентом. т.е. открытие диалога для изменения данных объекта. В onSave() dialogForm мне нужно было бы нажать новый editorState, но на данный момент он не находится в области видимости.

Есть ли способ получить доступ к editorState в рамках компонента декоратора или есть более разумное решение?

4 ответа

У меня нет четкого ответа (хотя это кажется хорошим вопросом!), Но я копался в примерах DraftJs, и пример TexEditor кажется, что он может быть полезен (если вы еще не обращались к нему). Он использует пользовательский блок, а затем передает реквизиты, которые обрабатывают обновление состояния редактора в ответ на изменения в компоненте блока.

Дайте мне знать, если вы найдете решение, я хотел бы знать, как вы подошли к нему в конце.

редактировать: я знаю, что вы ссылались на CompositeDecorator, но не смогли найти пример того, что вы описываете

Вы можете использовать фабричный метод при создании с вашим декоратором, т.е. вместо того, чтобы писать что-то вроде этого:

      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 ... />
}

Компоненты, украшенные PS, будут повторно визуализироваться только в том случае, если они были изменены, поэтому, если вы хотите повторно визуализировать их на основе состояния / свойств за пределами EditorState вам нужно будет запустить повторную визуализацию редактора, выполнив setState(() => ({ editorState: newEditorState }))- это довольно некрасиво, но мы мало что можем сделать, пока этот вопрос не будет решен.

Поэтому я просто столкнулся с этой проблемой и решил ее с помощью свойств декоратора.

{
  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)
  }, [])

Главное здесь то, что сам обратный вызов никогда не изменяется и использует статическую ссылку. Это делает его более оптимальным.

Это может (скорее всего, вызовет) проблемы с порядком рендеринга, если вы делаете что-то нажатием клавиши, однако для моих сценариев использования это сработало нормально. Если вы делаете что-то большее, чем просто небольшую настройку, я бы рекомендовал использовать blockRendererFn, который дает вам максимальную гибкость (с более сложным компромиссом).

Обратное тоже работает (хотя лично я не рекомендую обновлять editorState в декораторах).

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

Надеюсь, это имеет смысл!

Вы можете попробовать установить новый декоратор: 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 });
Другие вопросы по тегам