【问题标题】:React Meteor, reactive prop and inner stateReact Meteor、react prop 和内部状态
【发布时间】:2018-02-13 20:43:54
【问题描述】:

我有一个组件

import React, { Component } from 'react'
import { EditorState, convertToRaw } from 'draft-js'
import { Editor } from 'react-draft-wysiwyg'
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'
import draftToHtml from 'draftjs-to-html'

import toolbarOptions from './JpuriTextEditorOptions'

export default class TextEditor extends Component {
  state = {
    editorState: this.props.editorState
  }

  componentWillReceiveProps = nextProps => {
    console.warn('componentWillReceiveProps')
    console.log('nextProps.editorState', nextProps.editorState)
    console.log('this.props.editorState', this.props.editorState)

    this.setState({editorState: nextProps.editorState})
  }

  onEditorStateChange = editorState => this.setState({editorState})

  onBlur = () => this.props.onBlur({key: this.props.myKey, value: draftToHtml(convertToRaw(this.state.editorState.getCurrentContent()))})

  render () {
    return (
      <Editor
        wrapperClassName={this.props.wrapperClassName}
        editorClassName={this.props.editorClassName}
        toolbarClassName={`toolbarAbsoluteTop ${this.props.toolbarClassName}`}

        wrapperStyle={this.props.wrapperStyle}
        editorStyle={this.props.editorStyle}
        toolbarStyle={this.props.toolbarStyle}

        editorState={this.state.editorState}
        onEditorStateChange={this.onEditorStateChange}
        onChange={this.props.onChange}

        toolbarOnFocus
        toolbar={toolbarOptions}

        onFocus={this.props.onFocus}
        onBlur={this.onBlur}
        onTab={this.props.onTab}
      />
    )
  }
}

我向它传递了一个响应式道具,this.props.editorState 然后我将它设置在内部状态中以处理那里的更改。只有onBlur 我将更改保存到mongo db。

现在有一个问题。 每当我单击编辑器时,我都会多次看到 componentWillReceiveProps 日志。每次更改都会发生这种情况,因此我无法正确使用我的编辑器组件。因为每次点击和更改时,它的光标都会重置为第一个字母。

我正在使用这个draftjs库https://github.com/jpuri/react-draft-wysiwyg

编辑

问题的更多细节。 在构造函数或 componentDidMount 中将状态设置为 this.props.editorState 正在解决初始状态的问题。 但是仍然只剩下一个问题。 在另一个组件中,我具有直接与数据库一起使用的撤消重做功能。现在,如果我输入一些文字。模糊它我的更改已保存到数据库中,由于内部文本,我可以看到文本。但是,如果我单击撤消按钮,文本将从数据库中撤消,但是由于内部状态,它仍将在编辑器中可见。所以我必须刷新才能看到我的操作被撤消。 使用 componentWillReceiveProps 解决了这个问题,但是由于某种原因,每次状态更改时都会调用 componentWillReceiveProps,即使 props 没有更改。从而带来上述问题。

【问题讨论】:

  • 如果你在每个收到的新道具上设置状态,那你为什么要使用内部状态呢?

标签: javascript mongodb reactjs meteor draftjs


【解决方案1】:

如果您使用的是该组件的 受控 模式,那么您应该在内部设置状态,而不是通过 props 从外部设置。
例如,如果您在收到的每个新道具上设置状态,则没有理由使用内部状态。
根据他们的DOCS,您似乎正在遵循他们的受控EditorState 示例,除非您在每个新道具上覆盖您的状态。
我想如果你只是从componentWillReceiveProps 中删除这种行为 即设置状态:this.setState({editorState: nextProps.editorState})
它应该像预期的那样工作。

顺便说一下,这是他们的例子:

import React, { Component } from 'react';
import { EditorState } from 'draft-js';
import { Editor } from 'react-draft-wysiwyg';


class ControlledEditor extends Component {
  constructor(props) {
    super(props);
    this.state = {
      editorState: EditorState.createEmpty(),
    };
  }

  onEditorStateChange: Function = (editorState) => {
    this.setState({
      editorState,
    });
  };

  render() {
    const { editorState } = this.state;
    return (
      <Editor
        editorState={editorState}
        wrapperClassName="demo-wrapper"
        editorClassName="demo-editor"
        onEditorStateChange={this.onEditorStateChange}
      />
    )
  }
}

编辑
跟进您的评论,状态初始化通常在 constructor 中进行。
但是,当您想要异步初始化状态时,您不能也不应该在构造函数中(也不应该在 componentWillMount)中这样做,因为当异步操作完成时,render 方法已经被调用了。
最好的地方是 componentDidMount 或 eventHandlers,所以在你的情况下 onBlur eventHandler:
从'react'导入反应,{组件}; 从“draft-js”导入 { EditorState }; 从'react-draft-wysiwyg'导入{编辑器};

class ControlledEditor extends Component {
  constructor(props) {
    super(props);
    this.state = {
      editorState: EditorState.createEmpty(),
    };
  }

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

  onBlur = (event) => {
    // do async stuff here and update state
  };

  render() {
    const { editorState } = this.state;
    return (
      <Editor
        editorState={editorState}
        wrapperClassName="demo-wrapper"
        editorClassName="demo-editor"
        onEditorStateChange={this.onEditorStateChange}
        onBlur={this.onBlur}
      />
    )
  }
}

【讨论】:

  • 亲爱的 Sag1v 我的问题完全是关于使用外部道具和内部状态。我使用数据库中的外部道具并将其设置为初始状态。然后当用户开始输入时,我不想在用户输入时保存到数据库。因此,当用户完成输入(即onBlur)时,我将更改保存到数据库。这正是我需要再次使用外部道具初始化我的状态的时候。
  • 但是这样我仍然只有内部状态。如果用户刷新浏览器怎么办?他输入的文字不会丢失吗?
  • onBlur 处理程序上更新db 上的内容(例如我的评论“在此处执行异步操作并更新状态”)
  • 是的,但是我通过道具传递了数据库的保存状态,所以我需要以某种方式使用该道具设置状态,否则它将始终为空。
  • 你可以在两个地方做到这一点:1. componentDidMount 用于服务器的初始状态。 2. 在更新服务器后,在 ajax 回调中的 onBlur 事件处理程序上(不过,您可能会拥有与从 UI 更新服务器状态相同的状态,所以我认为没有必要再次更新 UI,因为它是相同的州)。
猜你喜欢
  • 2018-08-02
  • 2020-06-26
  • 2021-09-21
  • 2023-03-17
  • 1970-01-01
  • 2018-04-08
  • 2021-11-29
  • 2022-07-05
  • 1970-01-01
相关资源
最近更新 更多