ReactJS:如何在没有绑定的事件处理程序中访问我的模型?

时间:2014-07-17 05:13:41

标签: javascript reactjs

假设我有一个ReactJS组件,表示包含“段落”的“文档”,每个组件都包含“句子”,我想将其呈现到contenteditable span中。

var paragraphData = [{
  id: 1,
  sentenceData: [
    'Paragraph 1, Sentence 1',
    'Paragraph 1, Sentence 2'
  ]
},{
  id: 2,
  sentenceData: [
    'Paragraph 2, Sentence 1',
    'Paragraph 2, Sentence 2'
  ]
}];

var Sentence = React.createClass({
  render: function () {
    return (<span
              contenteditable="true"
              onKeyDown={this.props.onKeyDown}>
              {this.props.value}
            </span>);
  }
});

var Paragraph = React.createClass({
  render: function () {
    var me = this;
    var sentences = this.props.sentenceData.map(function (sentenceData) {
      return <Sentence value={sentenceData} onKeyDown={me.props.onKeyDown} />;
    });

    return <div>{sentences}</div>;
});

var Document = React.createClass({
  render: function () {
    var me = this;
    var paragraphs = this.props.paragraphData.map(function (paragraphData) {
      return <Paragraph sentences={paragraphData.sentenceData} onKeyDown={me.onKeyDown}>;
    });

    return <div>{paragraphs}</div>;
  },
  onKeyDown: function (e) {
    // If "Enter" is pressed, I want to split the sentence at
    // getSelection().focusOffset, update the current sentence's
    // value to currentValue.substr(0, focusOffset) and insert a
    // new sentence with value currentValue.substr(focusOffset),
    // but how do I know which paragraph/sentences I need to
    // inspect/change?  Is "e.target" the only thing I have to go by?
  }
});

在ReactJS中,我们的想法是让数据流动并使事件流下来。 (哪一个被称为“向上”或“向下”似乎一直在变化,但希望你知道我的意思。)

我的问题:

在我的onKeyDown处理程序中,我如何知道哪些模型需要应用更改?

我考虑使用.bind()将处理程序绑定到每个模型,因为它被传递出来,但它似乎有点......错误:

  • 这会被视为模型/视图之间的紧密耦合吗?
  • 这意味着绑定成百上千次(可能在大型文档上),每次创建一个新函数 - 这将违背最佳实践“不要在循环中创建函数”原则。

我感觉我正朝着错误的方向前进 - 任何帮助都非常感激!

2 个答案:

答案 0 :(得分:1)

绑定onKeyDown函数非常好。

如果您在shouldComponentUpdate中实施Sentence,那么当您的应用再次呈现时,将不会再次创建绑定的功能,因为如果这些组件没有更改,它们将无法呈现。

我认为1000或10000函数的内存开销不会产生太大影响,除非遇到性能问题,否则不应尝试对其进行优化。你不想要的是每次渲染时都创建所有这些函数,这就是shouldComponentUpdate在这里的原因。

它们不会将它们已经存在的组件耦合得更多(它们是因为它们已经在明确定义的业务环境中进行了交互)。基本上,您可以创建一个通用的,非耦合组件,它将接收任何数据,并且在关键数据呈现时,会将该数据注入回调。它是通用的,不添加耦合,您可以控制组件外部的整个行为。


请注意,绑定函数来自props或in循环到dom事件侦听器不是React禁止的,实际上你可以找到完成它的例子。

请注意,在React中,禁止重新绑定组件的函数,因为React将所有函数绑定到其组件。 因此,如果某个函数位于Document并注入Sentence,则无法将其绑定到this中的Sentence,因为它不会产生反应并被React禁止

这是代码:https://github.com/facebook/react/blob/95de877dceeaac08755cfe1142a853c467d91d58/src/core/ReactCompositeComponent.js#L1291

if (newThis !== component && newThis !== null) {
          monitorCodeUse('react_bind_warning', { component: componentName });
          console.warn(
            'bind(): React component methods may only be bound to the ' +
            'component instance. See ' + componentName
          );
        } 

请注意,已添加newThis !== null。在尝试绑定道具功能时,实际上已经添加了这个来解决这个问题。

现在你可以写了  <Sentence value={sentenceData} onKeyDown={me.props.onKeyDown.bind(null,sentenceData} />

在文档上你有一个听众: onKeyDown: function (sentenceData) { }

这非常好:)


请注意,还有另一种方法可以解决这个问题,这可能会更有效:

var Sentence = React.createClass({
  onKeyDown: function(e) {
     this.props.onKeyDown(this.props.value)
  },
  render: function () {
    return (<span
              contenteditable="true"
              onKeyDown={this.props.onKeyDown}>
              {this.props.value}
            </span>);
  }
});

您只需创建一个具有此通常绑定的唯一函数的类,而不是绑定函数。在这种情况下,我认为它会创建更多的耦合,因为您实际上并没有从Sentence组件外部控制回调的行为。

答案 1 :(得分:0)

你对自己的错误问题有所了解。

无论您指向的相关onKeyDown处理程序应该在哪里(即句子或段落),您都需要处理数据更改然后调用:

this.setState({stateName: newdata})

这将导致使用新数据重新呈现组件的反应。

举个好例子,请看facebook's tutorial for a comment widget

您可以通过添加新注释来查看表单如何处理数据更改,然后调用setState()以使用其他注释重新呈现。 React处理其他所有事情。

在您的示例中,如果您更改段落中的某些内容,则在您完成所需的所有工作后,段落应使用新的句子数据调用setState,然后做出反应将处理其余内容。