jquery - 在 Flux/React.js 中,在哪里初始化 jQuery 插件?

标签 jquery jquery-plugins reactjs reactjs-flux

Flux 模型要求在 View 中启动的任何状态更改都会通过调度程序触发操作,并沿着存储传播回监听 View 。

The Flux Model

这一切都很美好。但是,如果我需要在特定的状态更改之后执行某些 DOM 操作怎么办?在现实世界的应用程序中,我们有时必须使用称为 jQuery 插件遗迹(还记得那些吗?)

例如,我需要初始化一个 jQuery 视频播放器,$('#videoContainer').initPlayer(streamURL)在 Ajax 请求检索之后 streamURL在继续阅读之前,请花点时间弄清楚如何使用 Flux/React 做到这一点。

在 View 部分,我可能会使用componentWillReceiveProps:

var jsVideoPlayer = React.createClass({
  componentWillReceiveProps: function(nextProps) {
    $(this.refs.videoContainer.getDOMNode()).initPlayer(nextProps.streamURL);
  },
  render: function() {
    return (
      <div ref="videoContainer">
      </div>
    );
  }
});

但是在这里,每次状态更新时播放器都会被初始化。那肯定会破坏我们的视频播放器。因此,在实际执行任何操作之前,我们先检查一下 URL 是否已更改:

  componentWillReceiveProps: function(nextProps) {
    if (nextProps.streamURL && nextProps.streamURL !== this.streamURL) {
      this.streamURL = nextProps.streamURL;
      $(this.refs.videoContainer.getDOMNode()).initPlayer(nextProps.streamURL);
    }
  },

很简单,对吧?但更大的图景又如何呢?如果我们随着添加更多功能和 UI 元素而扩大范围,这可能会导致在 View 中出现更多关于商店中发布的内容的自定义验证代码。即使在一个完美的应用程序中,每个商店都有自己的域,并且所有内容都以设计模式一尘不染,达到值得专门宗教追随者的水平,随着应用程序的扩展,我们仍然必须在 View 中使用越来越多的逻辑.

在我们的团队中,我认为这个逻辑应该真正进入 ControllerView,它适合 Flux 模型 - 但其他人都认为这是框架应该处理的事情。我们是 Flux/React 的新手,无法想出更好的主意来让框架为我们做到这一点。

最佳答案

当您识别模式时,您可以创建抽象。这里的模式是需要以简单的方式处理变化的 Prop 。我已经思考这个问题有一段时间了...这就是我到目前为止所想到的。

propUpdates: {
  propName: {
    onMount: function(to, el, config){}
    onChange: function(from, to, el, config){},
    idempotent: false,
    compare: 'default'
  }
}

它可能仍然很冗长,但它更具声明性,并且不需要大量 if 语句和比较。 jsbin

var Test = React.createClass({
  mixins: [propUpdatesMixin],
  propUpdates: {
    text: {
      onChange: function(from, to, el){
        el.textContent = to;
      },
      idempotent: true
    }
  },
  render: function(){
    return <div />;
  }
});

onChange 仅在属性实际更改时调用。默认情况下,它与 === 进行比较,但是您可以指定“shallow”、“deep”的 compare 或一个采用旧的和新的 prop 值的函数,如果相等则返回 true。

如果幂等为true,则调用onChange来代替onMount,并且第一个参数未定义。 onChange 和 onMount 内部的 this 是组件实例。要获取具有 onChange/onMount/etc 属性的对象,请使用最后一个参数 (config)。

<小时/>

有时您需要更多的控制,例如当您需要对多个 Prop 的更改使用react时。

componentDidUpdate: function(prevProps){
  var changes = this.getPropsChanges(prevProps, this.props);
  if (changes.text.changed && changes.color.changed) {
    // ...
  }
}

getPropsChanges 的返回是 prop 名称到更改对象的映射。更改对象具有以下结构:

{
  changed: Boolean,
  from: Any,
  to: Any,
  name: String (prop name)
  config: {onMount,onChange,idempotent,compare}
}

mixin 的设计不会妨碍您。您可以混合搭配策略。它只需要一个 propUpdates,但它可以是 {}。您仍然可以编写自己的 componentDidMount 并仅对 onChange 使用 propUpdates,或者仅对 onMount 使用 propUpdates 并编写自己的 componentWillUpdate,或者为一个 prop 使用 onChange,为另一个 prop 使用 onMount,为第三个 prop 使用幂等 onChange,然后执行操作在 componentDidMount 和 componentDidUpdate 中。

尝试一下 jsbin看看它是否符合您的需求。为了完整起见,这里是 mixin 的完整代码。

var comparisons={"shallow":function(a,b){return Object.keys(a).every(function(key){return a[key]!==b[key]})},"deep":function(a,b){return!_.isEqual(a,b)},"default":function(a,b){return a!==b}};var EACH_PROP="__propUpdatesMixin_eachProp__";var PROPS="propUpdates";var propUpdatesMixin={};
propUpdatesMixin.componentDidMount=function(){var el=this.getDOMNode();this[EACH_PROP](function(propName,config,propValue){if(config.onMount)config.onMount.call(this,propValue,el,config);else if(config.onChange&&config.idempotent)config.onChange.call(this,undefined,propValue,el,config)},this.props)};
propUpdatesMixin.componentDidUpdate=function(prevProps){var el=this.getDOMNode();var changes=this.getPropsChanges(prevProps,this.props);Object.keys(changes).forEach(function(propName){var change=changes[propName];if(change.changed&&change.config.onChange)change.config.onChange.call(this,change.from,change.to,el,change.config)},this)};
propUpdatesMixin.getPropsChanges=function(propsA,propsB){var updates={};this[EACH_PROP](function(propName,config,a,b){var compare=typeof config.compare==="function"?config.compare:comparisons[config.compare]?comparisons[config.compare]:comparisons["default"];var changed=compare(a,b);updates[propName]={changed:changed,from:a,to:b,name:propName,config:config}},propsA,propsB);return updates};
propUpdatesMixin[EACH_PROP]=function(fn,propsA,propsB){propsA=propsA||{};propsB=propsB||{};Object.keys(this[PROPS]).map(function(propName){return fn.call(this,propName,this[PROPS][propName],propsA[propName],propsB[propName])},this)};

关于jquery - 在 Flux/React.js 中,在哪里初始化 jQuery 插件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27255517/

相关文章:

reactjs - 如何为 React 组件参数创建文字类型?

jquery - 在 bootstrap 中将标题添加到 has-feedback span

javascript - 如何修复 jQuery SlideToggle 动画故障?

javascript - jQuery - 从each() 函数访问所有元素

javascript - 在一个操作创建器中响应 redux 多个请求

reactjs - 希望使用 react 钩子(Hook)传递所有 Prop

javascript - jquery 函数未执行。我缺少什么

javascript - insertAdjacentHTML 未在 beforeend 之前添加

javascript - Google+ 样式自动完成 + 下拉 jQuery 插件

javascript - 在 jQuery 中,如何调用适用于加载事件的 `function`?