如何在React中“思考”这个复杂的例子?

时间:2015-10-11 17:54:44

标签: jquery meteor reactjs

事先道歉,这可能不是一个正确的解决方案类型的问题,但我不知道如何将其分解为更简单的部分或其他问题。

我在弥补在线提供的更简单的反应样本/演示之间的差距以及如何“为更复杂的应用程序做出反应”方面遇到了一些麻烦。

对于使用Meteor和一堆jquery构建的东西,我有一个预先存在的解决方案。这有点hacky,如果我能弄清楚如何,我认为对React进行重构是一个很好的选择。

看起来像这样:

enter image description here

如果我从breaking it down into a component hierarchy开始,我会得到以下内容:

enter image description here

  • 紫色 - 用户可编辑的HTML内容容器。用户可以通过WYSIWYG编辑器编辑容器中的任何html。
  • 黄色 - 在html容器中,html ... p的各个顶级块,列表,img被赋予唯一的ID - 因为WYSIWYG编辑器可能无法成为Purle的子组件
  • 绿色 - 渲染标记但最初对每个块都不可见。将鼠标悬停在一个块上或一个标记上会显示与该块相关联的标记。单击标记将开始添加操作的过程。如果块已经附加了一个线程,则立即渲染标记+计数(根据标记中的1)。标记都包含在红色
  • 海泡绿色 - 操作是单击标记并保存线程时添加的内容
  • 蓝色 - 所有内容的容器,称之为缺少更好名称的条目

现在,我的反应思维能力分崩离析。每个组件似乎与其他组件具有非常严重的相互依赖性。

标记看起来像是最好的作为自己的组件,但它们的状态更多地受到内部其他组件的控制。

  • 使用编辑器编辑HTML内容,该编辑器依赖于容器中的所有HTML为一个字符串,因此这些块无法真正分解为单独的组件。
  • 将鼠标悬停在内容块上会显示/隐藏标记,以便内容区域上的事件影响标记组件的状态。事件处于HTML块级别,尽管这些事件不一定是单个组件
  • 每个标记的存在与内容HTML区域中的内容块数量严格相关
  • 每个标记是否具有与之关联的Action与Action集合
  • 严格相关
  • 标记的正确定位取决于内容的呈现方式和/或重新调整大小
  • 单击标记会更改Action组件的状态,而反之亦然,(取消/删除和Action会更改标记的状态)。

你如何通过这种复杂性的例子来“思考反应”?任何帮助或建议将不胜感激。

2 个答案:

答案 0 :(得分:5)

我已经阅读了您的示例,并且我并不完全确定它是如何工作的,因此我只是尝试回答您的问题并从示例应用程序中提取一些具体示例。< / p>

  

现在,我的反应思维能力分崩离析。每个组件似乎与其他组件具有非常严重的相互依赖性。

因此,反应的基本概念是尽可能地保留东西作为道具,如果你有需要由多个组件共享的状态,你需要将状态抽象为父(或祖父)在他们之上。如果他们没有合适的父母来弥补这一差距,您可以创建另一个包含此状态的组件,并将它们都作为子级。如果您创建的树太大,那么这就是使用flux来解决其中一些问题的方法,但我不会在这里讨论这个问题,因为它可能更容易解决这个问题。从那里起反应并学习它,直到你遇到痛点。

例如,如果绿松石动作/线程组件受到标记点击的影响,则需要父级保持其上方的状态。

  

这些标记似乎最适合作为自己的组件,但它们的状态更多地受到内部其他组件的控制。

它们应该是它们自己的组件,并且可能是文本块的子组件。文本组件将采用支柱,以确定是否显示这些块。

一般建议

我认为通常最简单的尝试和建模的方法是从底部开始逐渐开始。从一切静态开始,一切都作为道具开始,当你开始需要互动时,你可以开始应用状态,并在你构建你的组件并转向状态时逐渐移动该状态。在子组件中成道具。只有这样我才能开始明白你的国家需要在哪里。

一些伪代码

我写了一些伪Javascript代码来直观地了解我将如何开始构建应用程序的这一部分。它不会做任何事情,但希望它能帮助你想象我的意思。如果您从ParentWithState开始关注,并通过渲染功能向孩子Marker方向前进,希望您能看到我的意思。

var Marker = React.createClass({
  render: function() {
    return (
      <div className="marker" onClick={this.props.handleMarkerEvent}>
        +
      </div>
    )
  }
})

var TextBlock = React.createClass({
  var markerData = this.props.markerData;
  var marker = null;

  //do some logic with markerData

  if(markerData.show === true){
    marker = <Marker handleMarkerEvent={this.props.handleMarkerEvent}>
  }

  render: function(){
    return (
      <div className="textBlock">
        {this.text}
        {marker}
      </div>
    )
  }
});

var Actions = React.createClass({
  render: function(){
    <div className="actions">
      //some code to display the actions
    </div>
  }
})

var ParentWithState = React.createClass({
  getInitialState: function(){
    return {
      textBlockData: [
        //textBlock data objects
      ],
      //put all the data you need for the app here 
    }
  },

  handleMarkerEvent: function(){
    //do some stuff when marker is clicked
    //change state which will propagate down
  },

  render: function() {
    var textBlocks = this.state.textBlockData.map(function(textBlock){
      return (
        <TextBlock text={textBlock.text} markerData={textBlock.markerData} markerEvent={this.handleMarkerEvent}>
      )
    })

    return (
      <div>
        <div className="text-blocks">
          {textBlocks}
        </div>
        <Actions />
      </div>
    )
  }
});

我在这里提到的最后一件事,因为Marker组件有一个影响其祖父母的状态的函数,我将在ParentWithState组件处创建事件处理程序然后将其作为道具传递下来,最后在孩子中我将使用onClick处理程序调用它,但实际上它是控制此函数的父级

答案 1 :(得分:-1)

您只需创建全局状态并使用它来呈现所有组件。看起来你错过了Flux来完成任务。