diff --git a/_data/nav_docs.yml b/_data/nav_docs.yml index 0401c717..7b562e28 100644 --- a/_data/nav_docs.yml +++ b/_data/nav_docs.yml @@ -50,6 +50,8 @@ title: Web Components - id: higher-order-components title: Higher-Order Components + - id: integrating-with-other-libraries + title: Integrating with Other Libraries - title: Reference items: - id: react-api diff --git a/docs/integrating-with-other-libraries.md b/docs/integrating-with-other-libraries.md new file mode 100644 index 00000000..4f393a97 --- /dev/null +++ b/docs/integrating-with-other-libraries.md @@ -0,0 +1,439 @@ +--- +id: integrating-with-other-libraries +title: Integrating with Other Libraries +permalink: docs/integrating-with-other-libraries.html +--- + +React can be used in any web application. It can be embedded in other applications and, with a little care, other applications can be embedded in React. This guide will examine some of the more common use cases, focusing on integration with [jQuery](https://jquery.com/) and [Backbone](http://backbonejs.org/), but the same ideas can be applied to integrating components with any existing code. + +## Integrating with DOM Manipulation Plugins + +React is unaware of changes made to the DOM outside of React. It determines updates based on its own internal representation, and if the same DOM nodes are manipulated by another library, React gets confused and has no way to recover. + +This does not mean it is impossible or even necessarily difficult to combine React with other ways of affecting the DOM, you just have to be mindful of what each are doing. + +The easiest way to avoid conflicts is to prevent the React component from updating. You can do this by rendering elements that React has no reason to update, like an empty `
`. + +### How to Approach the Problem + +To demonstrate this, let's sketch out a wrapper for a generic jQuery plugin. + +We will attach a [ref](/react/docs/refs-and-the-dom.html) to the root DOM element. Inside `componentDidMount`, we will get a reference to it so we can pass it to the jQuery plugin. + +To prevent React from touching the DOM after mounting, we will return an empty `
` from the `render()` method. The `
` element has no properties or children, so React has no reason to update it, leaving the jQuery plugin free to manage that part of the DOM: + +```js{3,4,8,12} +class SomePlugin extends React.Component { + componentDidMount() { + this.$el = $(this.el); + this.$el.somePlugin(); + } + + componentWillUnmount() { + this.$el.somePlugin('destroy'); + } + + render() { + return
this.el = el} />; + } +} +``` + +Note that we defined both `componentDidMount` and `componentWillUnmount` [lifecycle hooks](/react/docs/react-component.html#the-component-lifecycle). Many jQuery plugins attach event listeners to the DOM so it's important to detach them in `componentWillUnmount`. If the plugin does not provide a method for cleanup, you will probably have to provide your own, remembering to remove any event listeners the plugin registered to prevent memory leaks. + +### Integrating with jQuery Chosen Plugin + +For a more concrete example of these concepts, let's write a minimal wrapper for the plugin [Chosen](https://harvesthq.github.io/chosen/), which augments `` DOM node, it reads the attributes off of the original DOM node, hides it with an inline style, and then appends a separate DOM node with its own visual representation right after the `` wrapped in a `
`: + +```js{4,5} +class Chosen extends React.Component { + render() { + return ( +
+ +
+ ); + } +} +``` + +Notice how we wrapped `` node we passed to it. However, as far as React is concerned, `
` always only has a single child. This is how we ensure that React updates won't conflict with the extra DOM node appended by Chosen. It is important that if you modify the DOM outside of React flow, you must ensure React doesn't have a reason to touch those DOM nodes. + +Next, we will implement the lifecycle hooks. We need to initialize Chosen with the ref to the ` this.el = el}> +``` + +This is enough to get our component to render, but we also want to be notified about the value changes. To do this, we will subscribe to the jQuery `change` event on the ``, but we will also add a `componentDidUpdate()` lifecycle hook that notifies Chosen about changes in the children list: + +```js{2,3} +componentDidUpdate(prevProps) { + if (prevProps.children !== this.props.children) { + this.$el.trigger("chosen:updated"); + } +} +``` + +This way, Chosen will know to update its DOM element when the ` this.el = el}> + {this.props.children} + +
+ ); + } +} +``` + +[Try it on CodePen.](http://codepen.io/gaearon/pen/xdgKOz?editors=0010) + +## Integrating with Other View Libraries + +React can be embedded into other applications thanks to the flexibility of [`ReactDOM.render()`](/react/docs/react-dom.html#render). + +Although React is commonly used at startup to load a single root React component into the DOM, `ReactDOM.render()` can also be called multiple times for independent parts of the UI which can be as small as a button, or as large as an app. + +In fact, this is exactly how React is used at Facebook. This lets us write applications in React piece by piece, and combine it with our existing server-generated templates and other client-side code. + +### Replacing String-Based Rendering with React + +A common pattern in older web applications is to describe chunks of the DOM as a string and insert it into the DOM like so: `$el.html(htmlString)`. These points in a codebase are perfect for introducing React. Just rewrite the string based rendering as a React component. + +So the following jQuery implementation... + +```js +$('#container').html(''); +$('#btn').click(function() { + alert('Hello!'); +}); +``` + +...could be rewritten using a React component: + +```js +function Button() { + return ; +} + +ReactDOM.render( + ; +} + +function HelloButton() { + function handleClick() { + alert('Hello!'); + } + return