draft.js: 文本编辑器从其他组件的状态填充值

draft.js: text editor populate value from other component's state

我正在使用 draft.js 制作文本编辑器,我有两个组件:CreatePost.js 从后端获取 post 字段并使用用户填充状态输入和 TextEditor.js,其中包含我在 CreatePost.js 中使用的文本编辑器。文本编辑器应在 CreatePost.js onChange.

状态下填充 body 字段

我的问题是如何让文本编辑器填充其他组件中的状态?我需要使用道具吗?

之前,我在 CreatePost.js 中有一个文本区域填充了 body。我希望其他组件中的文本编辑器改为填充它。我试过使用 <TextEditor onChange={this.changeHandler} value={body} />CreatePost.js 中,但没有用。

console.log(body):

posts.js(控制器)

exports.create = (req, res) => {
  const { title, body, date } = req.body;
  const post = new Post({
    title,
    body,
    date,
    "author.id": req.profile._id,
    "author.name": req.profile.name,
  });
  post
    .save()
    .then((response) => {
      res.send(response);
    })
    .catch((err) => {
      return res.status(400).json({
        error: errorHandler(err),
      });
    });
};

CreatePost.js

class CreatePost extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      title: "",
      body: "",
      createdPost: "",
      error: "",
    };
  }

  changeHandler = (e) => {
    this.setState({ [e.target.name]: e.target.value });
  };

  submitHandler = (e) => {
    e.preventDefault();
    const {
      user: { _id },
    } = isAuthenticated();
    axios({
      url: `${API}/post/new-post/${_id}`,
      method: "POST",
      data: this.state,
    })
      .then((response) => {
        this.setState({ createdPost: this.state.title });
        return response;
      })
      .catch((error) => {
        if (!this.state.title || !this.state.body) {
          this.setState({
            error: "This post must contain a title and a body.",
          });
        }
        console.log(error);
      });
  };

...

  render() {
    const { title, body } = this.state;
    return (
      <>
        <Navbar />
        <Tabs>
          <TabList className="tabs">
            <Tab className="tab">Draft</Tab>
            <Tab className="tab">Preview</Tab>
          </TabList>
          <TabPanel>
            <div className="newpost_container">
              <form className="newpost_form" onSubmit={this.submitHandler}>
                <div className="form-group">
                  <input
                    type="text"
                    placeholder="Title"
                    name="title"
                    className="newpost_field newpost_title"
                    onChange={this.changeHandler}
                    value={title}
                  />
                </div>
                <div className="form-group newpost_body">
                <TextEditor />
                </div>
                <button className="btn publish-post-btn" type="submit">
                  Publish
                </button>
                {this.showSuccess()}
                {this.showError()}
              </form>
            </div>
          </TabPanel>

          <TabPanel>
            <div>
              <h1>{title}</h1>
              <div>{body}</div>
            </div>
          </TabPanel>
        </Tabs>
      </>
    );
  }
}

export default CreatePost;

TextEditor.js

class TextEditor extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      editorState: EditorState.createEmpty(),
    };
    this.plugins = [addLinkPlugin];
  }
  toggleBlockType = (blockType) => {
    this.onChange(RichUtils.toggleBlockType(this.state.editorState, blockType));
  };

  onChange = (editorState) => {
    this.setState({
      editorState,
    });
  };

  handleKeyCommand = (command) => {
    const newState = RichUtils.handleKeyCommand(
      this.state.editorState,
      command
    );
    if (newState) {
      this.onChange(newState);
      return "handled";
    }
    return "not-handled";
  };

// onClick for format options

  onAddLink = () => {
    const editorState = this.state.editorState;
    const selection = editorState.getSelection();
    const link = window.prompt("Paste the link -");
    if (!link) {
      this.onChange(RichUtils.toggleLink(editorState, selection, null));
      return "handled";
    }
    const content = editorState.getCurrentContent();
    const contentWithEntity = content.createEntity("LINK", "MUTABLE", {
      url: link,
    });
    const newEditorState = EditorState.push(
      editorState,
      contentWithEntity,
      "create-entity"
    );
    const entityKey = contentWithEntity.getLastCreatedEntityKey();
    this.onChange(RichUtils.toggleLink(newEditorState, selection, entityKey));
  };

  toggleBlockType = (blockType) => {
    this.onChange(RichUtils.toggleBlockType(this.state.editorState, blockType));
  };

  render() {
    return (
      <div className="editorContainer">
        <div className="toolbar">
          <BlockStyleToolbar
            editorState={this.state.editorState}
            onToggle={this.toggleBlockType}
          />
          // format buttons
        </div>

        <div>
          <Editor
            placeholder="Post Content"
            blockStyleFn={getBlockStyle}
            editorState={this.state.editorState}
            handleKeyCommand={this.handleKeyCommand}
            onChange={this.onChange}
            plugins={this.plugins}
            placeholder="Post Content"
          />
        </div>
      </div>
    );
  }
}

export default TextEditor;

看来您实际上已经非常接近解决这个问题了。使用 props 将更改处理程序发送到 TextEditor 时,您走在了正确的道路上。解决您的问题的一种方法是将 editorState 向上移动到 CreatePost 组件,然后向下传递值和更改处理程序。如果您这样做,您应该从 TextEditor 文件中删除 editorState 和它的更改处理程序。只要继续你的例子,像这样的东西应该可以工作,我还没有尝试过代码,但它应该可以帮助你朝着正确的方向前进。

CreatePost.js

constructor(props) {
    super(props);
    this.state = {
      title: "",
      body: EditorState.createEmpty(),
      createdPost: "",
      error: "",
    };
}

....

<TextEditor onChange={(value) => this.setState({ body: value })} editorState={body} />

TextEditor.js

<Editor
  placeholder="Post Content"
  blockStyleFn={getBlockStyle}
  editorState={this.props.editorState}
  handleKeyCommand={this.handleKeyCommand}
  onChange={this.props.onChange}
  plugins={this.plugins}
  placeholder="Post Content"
/>

发布数据时,我们需要访问编辑器的内容而不是 EditorState。我们可以通过 draft.js API 来做到这一点(在此处查看更多信息:https://draftjs.org/docs/api-reference-editor-state/#getcurrentcontent). And that's not enough unfortunately. We also need to to convert the content to a format that's easier to handle. We can do this with draft.js convertToRaw which you also need to import from the library (https://draftjs.org/docs/api-reference-data-conversion/#converttoraw)。转换为原始 returns JS 对象,因此我们还需要将其转换为字符串,然后才能使用 JSON.stringify().

将其发送到服务器
axios({
  url: `${API}/post/new-post/${_id}`,
  method: "POST",
  data: {
    ...this.state,
    body: JSON.stringify(convertToRaw(this.state.body.getCurrentContent()))
  }
})