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

Vee*_*era 3 javascript reactjs draftjs react-hooks

我有一个简单的用例:有一个 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} />;
};

Run Code Online (Sandbox Code Playgroud)

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

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

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

Ric*_*sen 7

基本问题是

const [editorState, setEditorState] = useState(initialState);
Run Code Online (Sandbox Code Playgroud)

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

当使用useState()并且有一个 prop(或其他)依赖项时,将它与 a 配对useEffect()以使事物具有反应性。

这可能看起来有点倒退,但很多(大部分)钩子都是关于在重新运行 Function 组件时保持相同的东西。所以useState()只能editorState通过setEditorState, 在初始调用后更新。

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} />;
};
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,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();
}
Run Code Online (Sandbox Code Playgroud)

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

不同之处在于自定义钩子在每次 Component 运行时都会运行,但editorState仍然只在 value 更改时更新。

定制挂钩

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();
}
Run Code Online (Sandbox Code Playgroud)

成分

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} />;
};
Run Code Online (Sandbox Code Playgroud)