Skip to content

与第三方库协同

React可以用于任何web应用中。它可以被嵌入到其他应用,且需要足以,其他的应用也可以嵌入到React中。

集成带有DOM操作的插件

React不理会React自身之外的DOM操作。它根据内部虚拟DOM来决定是否需要更新,而且如果同一个DOM节点被另一个库操作了。React会觉得困惑而且没有办法恢复。 这并不意味着React与其他操作DOM的方式不能结合,也不一定结合困难,只不过需要你去关注每个库所做的事情。 避免冲突的最简单方式就是防止React组件更新。你可以渲染无需更新的React元素,比如一个空的<div />

如果解决这个问题

一个用于通用的jQuery插件的wrapper。 添加一个ref到这个根DOM元素上,在componentDidMount中,我们能够获取它的引用这样我们就可以把它传递给jQuery插件了。 为了防止React在挂载之后去触碰这个DOM,我们会从render()函数中返回一个空的<div />。这个<div />元素既没有属性也没有子元素,所以React没有理由去更新它,使得jQery插件可以自由的管理这部分的DOM:

jsx
class SomePlugin extends React.Component {
    componentDidMount(){
        this.$el = $(this.el);
        this.$el = SomePlugin();
    }
    componentWillUnmount(){
        this.$el.SomePlugin('destroy')
    }

    render(){
        return <div ref={(el) =>this.el=el} />
    }
}

注意我们同时定义了componentDidMountcomponentWillUnmount生命周期函数。许多jQuery插件绑定事件监听到DOM上,所以在componentWillUnmount中注销监听是很重要的。如果这个插件每没有提供一个用于清理的方法,你可能会需要自己来提供一个,为了避免内存泄露要记得吧所有插件注册监听都移除掉。

和其他视图库集成

得益于ReactDOM.render()的灵活性,React可以被嵌入到其他的应用中。 虽然React通常被用来在启动的时候加载一个单独根React组件到DOM上,ReactDOM.render()同样可以在UI的独立部分上多次调用,这些部分可以小到一个按钮,也可以大到一个应用。

利于用React替换基于字符串的渲染

在旧的web应用中有一个通用的模式就是使用一个字符串描述DOM块,并且通过类似的html方法插入到DOM中。代码库中的这种例子是非常适合引入React的。直接把基于字符串渲染写成React组件即可。

txt

$("#container").html("<button id='btn'>Say Hello</button>")
txt

$("#btn").click(function(){
    alert('Hello')
})

可以使用React组件重写:

jsx

function Button(){
    return <button id="btn" > Say Hello </button>
}
jsx

ReactDom.render(
    <Button ></Button>,
    document.getElementById('container'),
    function(){
        $('#btn').click(function(){
            alert('Hello!')
        })
    }
)

从这起你可以开始把更多的逻辑移动到组件中,并开始应用更多通用的React实践。例如,在组建中最好不要依赖id,因为一个组件可能会被渲染多次。相反的,我们会使用React事件系统并且直接注册click处理函数到React的&lt;Button&gt;元素:

jsx
function Button(props){
    return <button onClick={props.onClick}> Say Hello</button>
}
jsx
function HelloButton(){
    function handleClick(){
        alert('hello')
    }

    return <Button onClick={handleClick}  />
}
jsx
ReactDOM.render(
    <HelloButton  />,
    document.getElementById('container'),
)

只要你喜欢你可以有不限数量的这种独立组件,并且使用ReactDOM.render()吧他们渲染到不同的容器中。逐渐的,随着你把越来越多的应用转化到React,你就可以吧他们结合成更大的组件,并且吧ReactDOM.render的调用移动到更上层的结构。

把React嵌入到Backbone视图

Backbone视图通常使用HTML字符串,或者产生字符串的模板函数,来创建DOM元素的内容,这个过程,同样的可以通过渲染一个React组件来替换掉。 如下,我们会创建一个名为ParagraphView的Backbone视图。他会重载Backbone的render()函数来渲染一个React&lt;Paragraph /&gt;组件到Backbone(this.el)提供的DOM元素中,同样使用ReactDOM.render():

jsx

function Paragraph(props) {
  return <p>{props.text}</p>;
}

const ParagraphView = Backbone.View.extend({
  render() {
    const text = this.model.get('text');
    ReactDOM.render(<Paragraph text={text}  />, this.el);
    return this;
  },
  remove() {
    ReactDOM.unmountComponentAtNode(this.el);
    Backbone.View.prototype.remove.call(this);
  }
});

remove方法中我们也需要调用ReactDOM.unmountComponentAtNode()以便在它解除的时候React清理组件树相关的事件处理的注册和其他资源。 当一个组件在React树中从内部删除的时候,清理工作是自动完成;但是因为我们现在手动(非React)移除整个树,我们必须手动调用这个方法。

和Model层集成

虽然通常是推荐使用单向数据流动的,例如React state,Flux或者Redux。React也可以使用一个其他框架和库的Model层。

在React组件中使用Backbone的Model

在React组件中使用Backbone的model和collection最简单的方法就是监听多种变化事件并且手动强制触发一个更新。 负责渲染model的组件会监听change事件,而负责渲染collection的组件需要监听add和remove事件。在这两种情况中,调用this.forceUpdate()来使用心得数据重新渲染组件。

jsx
class Item extend React.Component{
    constructor(props){
        super(props)
        this.handleChange=this.handleChange.bind(this);
    }
    handleChange(){
        this.forceUpdate()
    }
    componentDidMount(){
        this.props.model.on('change',this.handleChange)
    }
    componentWillUnmount(){
        this.props.model.off('change',this.handleChange)
    }
    render(){
        return <li>{this.props.model.get('text')}</li>
    }
}
jsx
class List extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange() {
    this.forceUpdate();
  }

  componentDidMount() {
    this.props.collection.on('add', 'remove', this.handleChange);
  }

  componentWillUnmount() {
    this.props.collection.off('add', 'remove', this.handleChange);
  }

  render() {
    return (
      <ul>
        {this.props.collection.map(model => (
          <Item key={model.cid} model={model}  />
        ))}
      </ul>
    );
  }
}

从model提取数据

我们会链接一个 NameInput React 组件到一个 Backbone model,并且每当输入框变化时更新它的 firstName 属性:

jsx
function NameInput(props) {
  return (
    <p>
      <input value={props.firstName} onChange={props.handleChange}  />
      <br  />
      My name is {props.firstName}.
    </p>
  );
}
jsx
const BackboneNameInput = connectToBackboneModel(NameInput);
jsx
function Example(props) {
  function handleChange(e) {
    props.model.set('firstName', e.target.value);
  }

  return (
    <BackboneNameInput
      model={props.model}
      handleChange={handleChange}
     />

  );
}
jsx
const model = new Backbone.Model({ firstName: 'Frodo' });
ReactDOM.render(
  <Example model={model}  />,
  document.getElementById('root')
);

你可以通过在生命周期方法中订阅其更改并,并选择性地,拷贝数据到本地 React state,来将 React 用于任何 model 库。