当父组件更改其值时,Draft JS 编辑器不会更新其内容?

Draft JS editor does not update it's content when its value changed by parent component?

我有一个简单的用例:有一个 DraftEditor 组件,它以 value 作为它的属性,并基于 value(空的或有内容的)创建一个编辑器状态。 value 有可能被父级更改,当它更改时,我希望草稿编辑器也能更新它的内容。这是我的 DraftEditor 组件。

import React, { useState } from "react";
import { Editor, EditorState, convertFromRaw } from "draft-js";

export default ({ value }) => {
  const initialState = value
    ? EditorState.createWithContent(convertFromRaw(JSON.parse(value)))
    : EditorState.createEmpty();
  const [editorState, setEditorState] = useState(initialState);

  return <Editor editorState={editorState} onChange={setEditorState} />;
};

问题:当父组件更新value时,Editor的内容没有更新。相反,它只显示初始化时使用的内容。我找到的解决方法是在 value 更改时手动调用 setEditorState,但我觉得这一步是不必要的,因为当组件重新呈现时我希望编辑器也重新计算它的内部状态?可能是我遗漏了什么?

知道为什么 Editor 没有更新它的内部状态吗?

这是一个代码沙箱:https://codesandbox.io/s/xenodochial-sanderson-i95vd?fontsize=14&hidenavigation=1&theme=dark

基本问题是

const [editorState, setEditorState] = useState(initialState);

只使用它的参数 initialState 一次(在初始 运行-through),无论 initialState 更改多少次。

当使用 useState() 并且存在 prop(或其他)依赖项时,将其与 useEffect() 配对以使其具有反应性。

这可能看起来有点倒退,但是很多(大部分)钩子都是关于在函数组件重新运行时保持不变的。因此 useState() 仅在初始调用后通过 setEditorState 更新 editorState

import React, { useState, useEffect } from "react";
import { Editor, EditorState, convertFromRaw } from "draft-js";

export default ({ value }) => {

  const [editorState, setEditorState] = useState();

  useEffect(() => {
    const state = value
      ? EditorState.createWithContent(convertFromRaw(JSON.parse(value)))
      : EditorState.createEmpty();
    setEditorState(state);
  }, [value]); // add 'value' to the dependency list to recalculate state when value changes.

  return <Editor editorState={editorState} onChange={setEditorState} />;
};

在上面的代码中,editorState 在初始组件调用时将为 null。如果这是 Editor 组件的问题,您可以在函数中外部化状态计算并为 useState()useEffect().

调用它
import React, { useState, useEffect } from "react";
import { Editor, EditorState, convertFromRaw } from "draft-js";

export default ({ value }) => {

  const [editorState, setEditorState] = useState(calcState(value));

  useEffect(() => {
    setEditorState(calcState(value));
  }, [value]); // add 'value' to the dependency list to recalculate state when value changes.

  return <Editor editorState={editorState} onChange={setEditorState} />;
};

const calcState = (value) => {
  return value
    ? EditorState.createWithContent(convertFromRaw(JSON.parse(value)))
    : EditorState.createEmpty();
}

由于这两个挂钩经常一起使用,我倾向于将它们配对在一个自定义挂钩中以封装细节。

不同之处在于,自定义挂钩 运行s 每次组件 运行s,但 editorState 仍然仅在值更改时更新。

自定义挂钩

import React, { useState, useEffect } from "react";
import { EditorState, convertFromRaw } from "draft-js";

export const useConvertEditorState = (value) => {

  const [editorState, setEditorState] = useState(calcState(value));

  useEffect(() => {
    setEditorState(calcState(value));
  }, [value]); 

  return [editorState, setEditorState];
}

const calcState = (value) => {
  return value
    ? EditorState.createWithContent(convertFromRaw(JSON.parse(value)))
    : EditorState.createEmpty();
}

组件

import React, { useState, useEffect } from "react";
import { Editor } from "draft-js";
import { useConvertEditorState } from './useConvertEditorState'

export default ({ value }) => {

  const [editorState, setEditorState] = useConvertEditorState(value);

  return <Editor editorState={editorState} onChange={setEditorState} />;
};