Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add guide on integrating with non-react code #9316

Merged
merged 42 commits into from Apr 26, 2017

Conversation

wacii
Copy link
Contributor

@wacii wacii commented Apr 2, 2017

One of the guides requested in #8060.

Discusses how to integrate with jQuery plugins in the abstract then provides a concrete example with Chosen. Moves on to Backbone, specifically how to render React components from Backbone views and two ways to consume Backbone models and collections from React.

Using Backbone views that way is not something I have done before. So hopefully I got that right.

@@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: please capitalize "other" and "libraries" for consistent style

title: Integrating with other libraries
permalink: docs/integrating-with-other-libraries.html
---

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a one-paragraph summary for this page? Something that says that React can be used in any application, and summarizing two methods below.


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. This can be done explicitly by returning false from [`componentWillUpdate()`](https://facebook.github.io/react/docs/react-component.html#componentwillupdate), or by rendering elements that have no reason to change.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit: please remove https://facebook.github.io from all links so that they stay relative to the root. This way they will resolve locally.

}

componentWillUnmount() {
// cleanup
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe let's omit it here if we're not showing anything. Or make "cleanup" more descriptive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A typical jQuery plugin might get cleaned up with $el.somePlugin("destroy") or similar.

Also, is it worth having the ref callback just save the element onto the class instance, and creating the jQuery wrapper in componentDidMount, for clarity?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't remember if somePlugin('destroy') was standard or not. That works out well as I wanted to mention the issue in the code without cluttering it with a full explanation.

As to saving the element instead of the wrapped element on the component, I'm not sure. Anyone familiar with jQuery will know the $variableName convention, and it is more performant to wrap it once. But jQuery isn't used nearly as much anymore, so is this still safe to assume? Should I go further and use jQuery(el) instead of $(el)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Various plugin libs have their own setup/destroy approaches, but I think $el.somePlugin("destroy") is a typical and clear enough example that it should go in there.

Using $ is absolutely clear, I'm just suggesting to do that as a separate step in componentDidMount so it's not kind of 'buried" in the ref callback. It'll also help illustrate that the normal use for a callback ref is to save the reference to the real DOM node.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. Do it in two steps. Sure. That is certainly neater.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, just:

componentDidMount() {
    this.$el = $(this.el);
    this.$el.somePlugin();
}

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

Or something along that line.


To demonstrate these concepts let's write a minimal wrapper for the plugin [Chosen](https://github.com/harvesthq/chosen), which augments `<select>` inputs.

Chosen does not render the initial select, so it is up to React to do so. What it does do is hide actual select and create its own control, notifying the original of changes using jQuery. Because it is Chosen maintaining the state, it is easiest to implement the wrapper using an [uncontrolled component.](https://facebook.github.io/react/docs/uncontrolled-components.html)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"What it does do" reads heavily, can we rephrase?


### Embedding React in a Backbone View

Creating a backbone wrapper around a react component is easy thanks to the flexibility of `ReactDOM.render()`. While a typical application usually calls the `render` method just once, it may be called repeatedly to update props or to create multiple component trees.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: capitalize backbone.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And React :)


### Embedding React in a Backbone View

Creating a backbone wrapper around a react component is easy thanks to the flexibility of `ReactDOM.render()`. While a typical application usually calls the `render` method just once, it may be called repeatedly to update props or to create multiple component trees.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to make the intro paragraph less about Backbone specifically, to make it clear the same applies to wrapping a React component in any imperative API. Maybe we could rename sections into "Integrating with DOM Manipulation Plugins" and "Integrating with Other View Libraries", explain the general idea in first paragraph of each, and then make jQuery and Backbone examples subheadings in them.

}

const ComponentView = Backbone.View.extend({
render() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For people unfamiliar with Backbone, worth adding a comment here that notes that in Backbone, render runs once and is responsible for constructing the DOM tree.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a section about rendering with strings/templates so the render function doesn't come out of nowhere. Not sure if that's enough.


```js
class ItemComponent extends React.Component {
rerender = () => this.forceUpdate();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same: let's only use ES6.

rerender = () => this.forceUpdate();

componentDidMount() {
this.props.model.on("change", rerender);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: single quotes everywhere

@gaearon
Copy link
Collaborator

gaearon commented Apr 2, 2017

That's an amazing PR, I love it! I'd like some changes but excited to get this in.

@gaearon gaearon mentioned this pull request Apr 2, 2017
13 tasks

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. This can be done explicitly by returning false from [`componentWillUpdate()`](https://facebook.github.io/react/docs/react-component.html#componentwillupdate), or by rendering elements that have no reason to change.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldComponentUpdate instead of componentWillUpdate?

@markerikson
Copy link
Contributor

This is a great PR! Valuable topic, and some good examples.

For additional reference info: my React/Redux links list has a section on wrapping non-React code, and I recently wrote a post showing how to use React components to control a 3D globe library (which doesn't even generate DOM elements, just draws to a WebGL canvas).

@selbekk
Copy link
Contributor

selbekk commented Apr 2, 2017

Amazing work!

@wacii
Copy link
Contributor Author

wacii commented Apr 3, 2017

Think I got all the little things. Added some sections to make the guide a bit more general. Those are more of a first draft. I will come back and polish in a couple days. If I linger now I'll just end up tinkering.

```js
class SomePlugin extends React.Component {
componentDidMount() {
this.$el = $(el);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be this.$el = $(this.el);

}
}
```
A [ref](/react/docs/refs-and-the-dom.html) is used to pass the underlying DOM element to the plugin. The `<div>` element has no properties or children, so React has no reason to update it.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth highlighting this a bit somehow. The key is that rendering a consistent set of elements each time means React won't be trying to make changes, so a lib that does modify the DOM can get away with it and not clash with React applying updates.

return (
<ul>
{this.props.collection.map(model => (
<ItemComponent model={model} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key?

}

componentDidMount() {
this.props.model.on('change', rerender);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.props.model.on('change', this.rerender);

@wacii
Copy link
Contributor Author

wacii commented Apr 19, 2017

Think I addressed all issues. Pens still need to be updated though.

const model = new Backbone.Model({ text: 'Sam' });
const handleChange = event => model.set('text', event.target.value);

<WrappedInput model={model} handleChange={handleChange} />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you still provide a whole example here? It’s fine to have a Demo component rendering WrappedInput. The only essential part is WrappedInput assignment should happen outside that component. (And you’d need to update the codepen too).

@wacii
Copy link
Contributor Author

wacii commented Apr 20, 2017

Updated the pens and gave the guide another pass.

For the Chosen example, I tried explaining the plugin in more detail and pulling back on how closely it was integrated with the React wrapper.

Are the pens expected to be exact copies of the code examples? I generally try adding a bit extra, both to take advantage of interaction and to demonstrate concepts I couldn't fit into the discussion.

@gaearon
Copy link
Collaborator

gaearon commented Apr 20, 2017

Are the pens expected to be exact copies of the code examples?

If inline code is a strict non-interrupting substring of the codepen it’s fine (e.g. we often skip the last ReactDOM.render even though it’s useful in this particular case).

It’s confusing if they have conflicting content though.

@wacii
Copy link
Contributor Author

wacii commented Apr 21, 2017

Alright then. The code examples and pens are basically the same now.

@gaearon
Copy link
Collaborator

gaearon commented Apr 26, 2017

I still think the Chosen section is problematic.
As a reader I would expect this to work, but it doesn't:

http://codepen.io/gaearon/pen/zwoVaY?editors=0011

(See two render calls at the bottom.)

@wacii
Copy link
Contributor Author

wacii commented Apr 26, 2017

Yeah, I had that working before, but Chosen acts strangely when you reset options after already selecting something, so I removed it. I'll look for another plugin to use.

@gaearon
Copy link
Collaborator

gaearon commented Apr 26, 2017

I slightly rewrote it for now so that changing the child options still works. Feel free to send further PRs to replace the example if you think it would be better. Great work! 👍

@gaearon gaearon merged commit 1816d06 into facebook:master Apr 26, 2017
gaearon pushed a commit that referenced this pull request Apr 26, 2017
* Add guide on integrating with non-react code

* Capitalize guide title

* Make links to other docs relative

* Rephrase 'What it does do'

* Remove experimental syntax

* Capitalize Backbone

* Remove empty lifecycle method in generic jQuery example

* Use shouldComponentUpdate() not componentWillUpdate()

* Prefer single quotes

* Add cleanup to generic jQuery example

* Capitalize React

* Generalize the section on Backbone Views

* Generalize the section on Backbone Models, a little

* Add introduction

* Adjust wording

* Simplify ref callbacks

* Fix typo in generic jQuery example

* Fix typos in Backbone models in React components

* Fix more typos in Backbone models in React components

* Add generic section on integrating with other view libraries

* Stress the benefits of an unchanging React element

* Small changes to introduction

* Add missing semicolon

* Revise generic jQuery wrapper section

Moved the section on using empty elements to prevent conflicts above the
code example and added brief introduction to that example.

* Add usage example for Chosen wrapper

* Prevent Chosen wrapper from updating

* Note that sharing the DOM with plugins is not recommended

* Mention how React is used at Facebook

* Mention React event system in template rendering section

* Remove destructuring from function parameters

* Do not name React components Component

* Elaborate on unmountComponentAtNode()

* Mention preference for unidirectional data flow

* Rename backboneModelAdapter

* Replace rest syntax

* Respond to updated model in connectToBackboneModel

* Rewrite connectToBackboneModel example

* Rework connectToBackboneModel example

* Misc changes

* Misc changes

* Change wording

* Tweak some parts

(cherry picked from commit 1816d06)
flarnie pushed a commit to flarnie/react that referenced this pull request Jun 7, 2017
* Add guide on integrating with non-react code

* Capitalize guide title

* Make links to other docs relative

* Rephrase 'What it does do'

* Remove experimental syntax

* Capitalize Backbone

* Remove empty lifecycle method in generic jQuery example

* Use shouldComponentUpdate() not componentWillUpdate()

* Prefer single quotes

* Add cleanup to generic jQuery example

* Capitalize React

* Generalize the section on Backbone Views

* Generalize the section on Backbone Models, a little

* Add introduction

* Adjust wording

* Simplify ref callbacks

* Fix typo in generic jQuery example

* Fix typos in Backbone models in React components

* Fix more typos in Backbone models in React components

* Add generic section on integrating with other view libraries

* Stress the benefits of an unchanging React element

* Small changes to introduction

* Add missing semicolon

* Revise generic jQuery wrapper section

Moved the section on using empty elements to prevent conflicts above the
code example and added brief introduction to that example.

* Add usage example for Chosen wrapper

* Prevent Chosen wrapper from updating

* Note that sharing the DOM with plugins is not recommended

* Mention how React is used at Facebook

* Mention React event system in template rendering section

* Remove destructuring from function parameters

* Do not name React components Component

* Elaborate on unmountComponentAtNode()

* Mention preference for unidirectional data flow

* Rename backboneModelAdapter

* Replace rest syntax

* Respond to updated model in connectToBackboneModel

* Rewrite connectToBackboneModel example

* Rework connectToBackboneModel example

* Misc changes

* Misc changes

* Change wording

* Tweak some parts

(cherry picked from commit 1816d06)
flarnie added a commit that referenced this pull request Jun 7, 2017
In order to ensure consistency between the 15-stable and 15.6 branches, we found all the diffs present only in 15-stable and cherry-picked them onto 15.6-dev.

These are 100% documentation updates, which is why we didn't bother cherry-picking them in the first place, but having them on the 15.6-dev branch makes the two branches more consistent and that is better.

Nobody will accidentally see outdated docs on the 15.6-dev branch
these diffs won't somehow be lost or overwritten when we combine the branches to release 15.6.
Test Plan:
Manually tested the docs, looking at many of the updated pages. Also ran all tests etc.
Changelog below:
---

* Fix the proptypes deprecation warning url on the "Don't Call PropTypes Warning" doc page (#9419)

* Use the same prop-types link on the warning docs page as the main proptypes doc page

* Link to repo instead

* Docs: Clarification of setState() behavior (#9329)

* Clarification of setState() behavior

`setState()` is a frequent source of confusion for people new to React, and I believe part of that is due to minimization of the impact of the asynchronous behavior of `setState()` in the documentation. This revision is an attempt to clarify that behavior. For motivation and justification, see [setState Gate](https://medium.com/javascript-scene/setstate-gate-abc10a9b2d82).

* Update reference-react-component.md

* Signature fix

* Update to address @acdlite concerns

* Add more details

* Update proptypes doc (#9391)

* Update proptypes doc

* Removed note

* Add tabs to installation page (#9275, #9277) (#9401)

* Add tabs to installation page (#9275, #9277)

This adds tabs for create-react-app and existing apps to the installation section of the docs. The tab implementation is a simplified version of React Native's installation page.

Fixes #9275.

* Use classList instead of className

* Use same implementation as in RN

* Refractor docs to indicate that state set to props in constructor will not recieve the updated props (#9404)

* Switch Installation to a tab when hash is present (#9422)

* Updated the Good First Bug section in readme (#9429)

* Updated the Good First Bug section in readme

* Inconsistent use of quotes. Prefered single quotes instead of double quotes

* Updated Good first bug link in how_to_contribute doc.

* Undo JSX attribute quote change

* don't capitalize "beginner friendly issue"

(cherry picked from commit 36c935c)

* [Documentation] Impreove the react-component section of doc (#9349)

* Impreove react-component of doc

[#9304](#9304)

* update description

* add missing space

(cherry picked from commit 359f5d2)

* Unique headings for linking purposes (#9259)

Previously two headings were 'Javascript Expressions' - now 'Javascript
Expressions as Props' and 'Javascript Expressions as Children'
(cherry picked from commit 363f6cb)

* Update jsx-in-depth.md (#9178)

* Update jsx-in-depth.md

Line 9 isn't changed

* Move selection down

* Fix

(cherry picked from commit ccb38a9)

* Sort out conferences by date (#9172)

(cherry picked from commit 37f9e35)

* Lift state up - Updating the documentation to mention that onClick is a synthetic event handler (#9427)

* Lift state up - Updating the documentation to mention that onClick is a synthetic event handler

* Review comments - Rephrase to handle synthetic events and event handler patterns

* Tweak

(cherry picked from commit 53a3939)

* Fixed grammar (#9432)

* Update codebase-overview.md

* Some more fixes

(cherry picked from commit d724115)

* [Tutorial] ES6, installation, and button closing tag (#9441)

* adds notes to tutorial on es6 and installation

* fixes tutorial mention of opening button tag

* More writing

* Update

* Minor tweaks to tutorial

* Fix duplicate sentence

* Minor tutorial nits

* Add missing tutorial sidebar links

* Tweak tutorial structure

* FIX: Move CRA build info under it's tab page (#9452)

* FIX: Move CRA build info under it's tab page

* Add some links

* Reorganize the "following along" instructions (#9453)

* Reorganize the "following along" instructions

* Minor tweaks

(cherry picked from commit 1ce562e)

* [Docs] Add accessibility to tabs in installation documentation (#9431)

* Add accessibility to tabs in installation documentation

* Change color and fix styling

(cherry picked from commit 9526174)

* [Docs: Installation] Fix tabs responsive layout - Resubmit (#9458)

* [Docs: Installation] Fix tabs responsive layout

* Move tabs a pixel down

* Remove left margin on first tab

* Remove the long line

* Fix mobile styles

(cherry picked from commit a92128e)

* Add more details in jsx-in-depth.md (#9006)

* jsx-in-depth.md add ternary statement for javascript expressions section

* jsx-in-depth.md add explanation to get falsey values for props

* update jsx-in-depth.md

* ensure links work locally, remove section about falsey prop values

* Fix links

* Add link to 'Typechecking with PropTypes' under 'Advanced Guides' (#9472)

This should have been retained in our docs, since PropTypes are only
moved and not deprecated.

Partially handles #9467, and I'll make a separate PR to
https://github.com/reactjs/prop-types to add more docs to the README
there.
(cherry picked from commit 39ca8aa)

* Updates how-to-contribute.md to use JSFiddle referenced in submit Git issue template (#9503)

(cherry picked from commit c8a64e2)

* Describe fixtures dir in the codebase overview (#9516)

* Describe fixtures dir in overview

* Fix folder name

(cherry picked from commit d12c41c)

* adds indirect refs to docs (#9528)

* adds indirect refs to docs

* Add more info

* Explain clearer

* Rephrase

* Update refs-and-the-dom.md

* Update refs-and-the-dom.md

* Update refs-and-the-dom.md

* Update refs-and-the-dom.md

* Update refs-and-the-dom.md

* Update refs-and-the-dom.md

* Update refs-and-the-dom.md

* Update refs-and-the-dom.md

* Update refs-and-the-dom.md

* Update refs-and-the-dom.md

* Update refs-and-the-dom.md

(cherry picked from commit 14fa8a5)

* Add reference to the Hyperscript libraries (#9517)

* Add reference to the Hyperscript libraries

I feel these should be mentioned as they provide terser syntax than using `R.createElement` directly, even with a shorthand.

* Rephrase

(cherry picked from commit a8c223a)

* [Docs] Fix confusing description for the <script>...</script> usage (#9502)

* Fix confusing description for the <script>...</script> usage

* Update jsx-in-depth.md

* Update reference-react-dom-server.md

* Update reference-react-dom.md

* Update reference-react.md

(cherry picked from commit 3d60d4c)

* [site] Load libraries from unpkg (#9499)

* [site] Load libraries from unpkg

* Revert Gemfile changes

(cherry picked from commit cf24d87)

* fixed error formatting in live editor (#9497)

(cherry picked from commit 7ccfb07)

* React.createElement syntax (#9459)

* React.createElement syntax

Added React.createElement syntax.
I think this is required for this tutorial.

* Reword

(cherry picked from commit 9824d52)

* Add guide on integrating with non-react code (#9316)

* Add guide on integrating with non-react code

* Capitalize guide title

* Make links to other docs relative

* Rephrase 'What it does do'

* Remove experimental syntax

* Capitalize Backbone

* Remove empty lifecycle method in generic jQuery example

* Use shouldComponentUpdate() not componentWillUpdate()

* Prefer single quotes

* Add cleanup to generic jQuery example

* Capitalize React

* Generalize the section on Backbone Views

* Generalize the section on Backbone Models, a little

* Add introduction

* Adjust wording

* Simplify ref callbacks

* Fix typo in generic jQuery example

* Fix typos in Backbone models in React components

* Fix more typos in Backbone models in React components

* Add generic section on integrating with other view libraries

* Stress the benefits of an unchanging React element

* Small changes to introduction

* Add missing semicolon

* Revise generic jQuery wrapper section

Moved the section on using empty elements to prevent conflicts above the
code example and added brief introduction to that example.

* Add usage example for Chosen wrapper

* Prevent Chosen wrapper from updating

* Note that sharing the DOM with plugins is not recommended

* Mention how React is used at Facebook

* Mention React event system in template rendering section

* Remove destructuring from function parameters

* Do not name React components Component

* Elaborate on unmountComponentAtNode()

* Mention preference for unidirectional data flow

* Rename backboneModelAdapter

* Replace rest syntax

* Respond to updated model in connectToBackboneModel

* Rewrite connectToBackboneModel example

* Rework connectToBackboneModel example

* Misc changes

* Misc changes

* Change wording

* Tweak some parts

(cherry picked from commit 1816d06)

* Don't build gh-pages branch on CircleCI (#9442)
flarnie pushed a commit that referenced this pull request Jun 12, 2017
* Add guide on integrating with non-react code

* Capitalize guide title

* Make links to other docs relative

* Rephrase 'What it does do'

* Remove experimental syntax

* Capitalize Backbone

* Remove empty lifecycle method in generic jQuery example

* Use shouldComponentUpdate() not componentWillUpdate()

* Prefer single quotes

* Add cleanup to generic jQuery example

* Capitalize React

* Generalize the section on Backbone Views

* Generalize the section on Backbone Models, a little

* Add introduction

* Adjust wording

* Simplify ref callbacks

* Fix typo in generic jQuery example

* Fix typos in Backbone models in React components

* Fix more typos in Backbone models in React components

* Add generic section on integrating with other view libraries

* Stress the benefits of an unchanging React element

* Small changes to introduction

* Add missing semicolon

* Revise generic jQuery wrapper section

Moved the section on using empty elements to prevent conflicts above the
code example and added brief introduction to that example.

* Add usage example for Chosen wrapper

* Prevent Chosen wrapper from updating

* Note that sharing the DOM with plugins is not recommended

* Mention how React is used at Facebook

* Mention React event system in template rendering section

* Remove destructuring from function parameters

* Do not name React components Component

* Elaborate on unmountComponentAtNode()

* Mention preference for unidirectional data flow

* Rename backboneModelAdapter

* Replace rest syntax

* Respond to updated model in connectToBackboneModel

* Rewrite connectToBackboneModel example

* Rework connectToBackboneModel example

* Misc changes

* Misc changes

* Change wording

* Tweak some parts

(cherry picked from commit 1816d06)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants