From 988efdee73b88760daacfc4e955122f7baac8880 Mon Sep 17 00:00:00 2001 From: petehunt Date: Fri, 12 Jul 2013 15:10:15 -0700 Subject: [PATCH] Reorg docs, write a lot of content, import a lot of stuff from dex --- docs/refactor/00-table-of-contents.md | 14 +- docs/refactor/02-displaying-data.md | 2 + ...md => 03-interactivity-and-dynamic-uis.md} | 6 +- docs/refactor/04-scaling-up.md | 69 ++++++++-- ...-building-effective-reusable-components.md | 86 ++++++++++++ docs/refactor/06-forms.md | 119 ++++++++++++++++ docs/refactor/07-working-with-the-browser.md | 113 +++++++++++++++ docs/refactor/07.1-more-about.refs.md | 130 ++++++++++++++++++ 8 files changed, 518 insertions(+), 21 deletions(-) rename docs/refactor/{03-handling-user-input.md => 03-interactivity-and-dynamic-uis.md} (94%) create mode 100644 docs/refactor/05-building-effective-reusable-components.md create mode 100644 docs/refactor/06-forms.md create mode 100644 docs/refactor/07-working-with-the-browser.md create mode 100644 docs/refactor/07.1-more-about.refs.md diff --git a/docs/refactor/00-table-of-contents.md b/docs/refactor/00-table-of-contents.md index a1a05c1f..7633064b 100644 --- a/docs/refactor/00-table-of-contents.md +++ b/docs/refactor/00-table-of-contents.md @@ -19,7 +19,7 @@ Displaying data - Components are just functions - JSX syntax (link to separate doc?) -Handling user input +Interactivity and dynamic UIs - Click handler example - Event handlers / synthetic events (link to w3c docs) - Under the hood: autoBind and event delegation (IE8 notes) @@ -32,22 +32,25 @@ Scaling up: using multiple components - Motivation: separate concerns - Composition example - Ownership (and owner vs. parent) +- Children - Data flow (one-way data binding) - A note on performance + +Building effective reusable components - You should build a reusable component library (CSS, testing etc) - Prop validation +- Transferring props: a shortcut - Mixins - Testing Forms -- TODO list example -- How to think about Reactive forms -- New form events and properties Working with the browser +- The mock DOM - Refs / getDOMNode() +- More about refs - Component lifecycle -- Polyfills +- Browser support and polyfills Integrating with other UI libraries - Using jQuery plugins @@ -78,3 +81,4 @@ Reference - API - DOM differences - JSX gotchas +- Antipatterns diff --git a/docs/refactor/02-displaying-data.md b/docs/refactor/02-displaying-data.md index 14c6ca17..ae808822 100644 --- a/docs/refactor/02-displaying-data.md +++ b/docs/refactor/02-displaying-data.md @@ -53,6 +53,8 @@ setInterval(function() { View the finished code in a web browser and type your name into the text field. Notice that React is only changing the time string in the UI -- any input you put in the text field remains, even though you haven't written any code to manage this behavior. React figures it out for you and does the right thing. +The way it is able to figure this out is that React does not directly manipulate the DOM, **it uses a fast, internal mock DOM to perform diffs and computes the most efficient DOM mutation for you.** + The inputs to this component are called `props` -- short for "properties". They're passed as attributes in JSX syntax. You should think of these as immutable within the component, that is, **never write to this.props**. ## Components are just like functions diff --git a/docs/refactor/03-handling-user-input.md b/docs/refactor/03-interactivity-and-dynamic-uis.md similarity index 94% rename from docs/refactor/03-handling-user-input.md rename to docs/refactor/03-interactivity-and-dynamic-uis.md index 030a15a7..f29752f1 100644 --- a/docs/refactor/03-handling-user-input.md +++ b/docs/refactor/03-interactivity-and-dynamic-uis.md @@ -1,4 +1,4 @@ -# Handling User Input +# Interactivity and dynamic UIs You've already [learned how to display data](./02-displaying-data.html) with React. Now let's look at how to make our UIs interactive. @@ -34,6 +34,8 @@ React.renderComponent( With React you simply pass your event handler as a camelCased prop similar to how you'd do it in normal HTML. React ensures that all events behave identically in IE8 and above by implementing a synthetic event system. That is, React knows how to bubble and capture events according to the spec, and the events passed to your event handler are guaranteed to be consistent with [the W3C spec](http://www.w3.org/TR/DOM-Level-3-Events/), regardless of which browser you're using. +**If you'd like to use React on a touch device** (i.e. a phone or tablet), simply call `React.initializeTouchEvents(true);` to turn them on. + ## Under the hood: autoBind and event delegation Under the hood React does a few things to keep your code performant and easy to understand. @@ -62,4 +64,4 @@ A common pattern is to create several stateless components that just render data ## What should go in state? -**`this.state` should contain any data that the component's event handlers will change that should trigger a UI update.** In real apps this data tends to be very small and JSON-serializable. When building a stateful component, think about the minimal possible representation of its state, and only store those properties in `this.state`. Inside of `render()` simply compute any other information you need based on this state. You'll find that thinking about and writing applications in this way tends to lead to the most correct application, since adding redundant or computed values to state means that you need to explicitly keep them in sync rather than rely on React computing them for you. \ No newline at end of file +**`this.state` should contain any data that the component's event handlers will change that should trigger a UI update.** In real apps this data tends to be very small and JSON-serializable. When building a stateful component, think about the minimal possible representation of its state, and only store those properties in `this.state`. Inside of `render()` simply compute any other information you need based on this state. You'll find that thinking about and writing applications in this way tends to lead to the most correct application, since adding redundant or computed values to state means that you need to explicitly keep them in sync rather than rely on React computing them for you. diff --git a/docs/refactor/04-scaling-up.md b/docs/refactor/04-scaling-up.md index 6fe5f7b5..209ce4c4 100644 --- a/docs/refactor/04-scaling-up.md +++ b/docs/refactor/04-scaling-up.md @@ -54,30 +54,71 @@ In the above example, instances of `Avatar` *own* instances of `ProfilePic` and It's important to draw a distinciton between the owner-ownee relationship and the parent-child relationship. The owner-ownee relationship is specific to React, while the parent-child relationship is simply the one you know and love from the DOM. In the example above, `Avatar` owns the `div`, `ProfilePic` and `ProfileLink` instances, and `div` is the **parent** (but not owner) of the `ProfilePic` and `ProfileLink` instances. -## Data flow +## Children -In React, data flows from owner to owned component through `props` as discussed above. This is effectively one-way data binding: owners bind their owned component's props to some value the owner has computed based on its `props` or `state`. Since this process happens recursively, data changes are automatically reflected everywhere they are used. +When you create a React component instance, you can include additional React components or JavaScript expressions between the opening and closing tags like this: -## A note on performance +```javascript + +``` -You may be thinking that it's expensive to react to changing data if there are a large number of nodes under an owner. The good news is that JavaScript is fast and `render()` methods tend to be quite simple, so in most applications this is extremely fast. Additionally, the bottleneck is almost always the DOM mutation and not JS execution, and React will optimize this for you using batching and change detection. +`Parent` can read its children by accessing the special `this.props.children` prop. -However, sometimes you really want to have fine-grained control over your performance. In that case, simply override `shouldComponentUpdate()` to return false when you want React to skip processing of a subtree. See [the React API docs](./api.html) for more information. +### Child Reconciliation -**Note:** if `shouldComponentUpdate()` returns false when data has actually changed, React can't keep your UI in sync. Be sure you know what you're doing while using it, and only use this function when you have a noticeable performance problem. Don't underestimate how fast JavaScript is relative to the DOM. +> Reconciliation is the process by which React updates the DOM with each new render pass. -## Build reusable component libraries! +In general, children are reconciled according to the order in which they are rendered. For example, suppose two render passes generate the following respective markup: -When designing interfaces, break down the common design elements (buttons, form fields, layout components, etc) into reusable components with well-defined interfaces. That way, the next time you need to build some UI you can write much less code, which means faster development time, less bugs, and less bytes down the wire. +```html +// Render Pass 1 +

Paragraph 1

Paragraph 2

+// Render Pass 2 +

Paragraph 2

+``` + +Intuitively, `

Paragraph 1

` was removed. Instead, React will reconcile the DOM by changing the text content of the first child and destroying the last child. React reconciles according to the *order* of the children. -## Prop validation +### Stateful Children -As your app grows it's helpful to ensure that your components are used correctly. We do this using `propTypes`. +For most components, this is not a big deal. However, for stateful components that maintain data in `this.state` across render passes, this can be very problematic. -** TODO zpao ** +In most cases, this can be sidestepped by hiding elements instead of destroying them: + +```html +// Render Pass 1 +

Paragraph 1

Paragraph 2

+// Render Pass 2 +

Paragraph 1

Paragraph 2

+``` -## Mixins +### Dynamic Children -Components are the best way to reuse code in React, but sometimes very different components may share some common functionality. These are sometimes called [cross-cutting concerns](http://en.wikipedia.org/wiki/Cross-cutting_concern). React provides `mixins` to solve this problem. +The situation gets more complicated when the children are shuffled around (as in search results) or if new components are added onto the front of the list (as in streams). In these cases where the identity and state of each child must be maintained across render passes, you can uniquely identify each child by assigning it a `key`: -One common use case is a component wanting to update itself on a time interval. It's easy to use `setInterval()`, but it's important to cancel your interval when you don't need it anymore. React provides [lifecycle methods](./06-working-with-the-browser.html) \ No newline at end of file +```javascript + render: function() { + var results = this.props.results; + return ( +
    + {this.results.map(function(result) { + return
  1. {result.text}
  2. ; + })} +
+ ); + } +``` + +When React reconciles the keyed children, it will ensure that any child with `key` will be reordered (instead of clobbered) or destroyed (instead of reused). + +## Data flow + +In React, data flows from owner to owned component through `props` as discussed above. This is effectively one-way data binding: owners bind their owned component's props to some value the owner has computed based on its `props` or `state`. Since this process happens recursively, data changes are automatically reflected everywhere they are used. + +## A note on performance + +You may be thinking that it's expensive to react to changing data if there are a large number of nodes under an owner. The good news is that JavaScript is fast and `render()` methods tend to be quite simple, so in most applications this is extremely fast. Additionally, the bottleneck is almost always the DOM mutation and not JS execution, and React will optimize this for you using batching and change detection. + +However, sometimes you really want to have fine-grained control over your performance. In that case, simply override `shouldComponentUpdate()` to return false when you want React to skip processing of a subtree. See [the React API docs](./api.html) for more information. + +**Note:** if `shouldComponentUpdate()` returns false when data has actually changed, React can't keep your UI in sync. Be sure you know what you're doing while using it, and only use this function when you have a noticeable performance problem. Don't underestimate how fast JavaScript is relative to the DOM. diff --git a/docs/refactor/05-building-effective-reusable-components.md b/docs/refactor/05-building-effective-reusable-components.md new file mode 100644 index 00000000..4250332c --- /dev/null +++ b/docs/refactor/05-building-effective-reusable-components.md @@ -0,0 +1,86 @@ +## Build reusable component libraries! + +When designing interfaces, break down the common design elements (buttons, form fields, layout components, etc) into reusable components with well-defined interfaces. That way, the next time you need to build some UI you can write much less code, which means faster development time, less bugs, and less bytes down the wire. + +## Prop validation + +As your app grows it's helpful to ensure that your components are used correctly. We do this using `propTypes`. + +** TODO zpao ** + +## Transferring props: a shortcut + +A common type of React component is one that extends a basic HTML in a simple way. Often you'll want to copy any HTML attributes passed to your component to the underlying HTML element to save typing. React provides `transferPropsTo()` to do just this. + +```javascript +/** @jsx React.DOM */ + +var CheckLink = React.createClass({ + render: function() { + // transferPropsTo() will take any props pased to CheckLink + // and copy them to + return this.transferPropsTo({'√ '}{this.props.children}); + } +}); + +React.renderComponent( + + Click here! + , + document.getElementById('example') +); +``` + +## Mixins + +Components are the best way to reuse code in React, but sometimes very different components may share some common functionality. These are sometimes called [cross-cutting concerns](http://en.wikipedia.org/wiki/Cross-cutting_concern). React provides `mixins` to solve this problem. + +One common use case is a component wanting to update itself on a time interval. It's easy to use `setInterval()`, but it's important to cancel your interval when you don't need it anymore to save memory. React provides [lifecycle methods](./06-working-with-the-browser.html) that let you know when a component is about to be created or destroyed. Let's create a simple mixin that uses these methods to provide an easy `setInterval()` function that will automatically get cleaned up when your component is destroyed. + +```javascript +/** @jsx React.DOM */ + +var SetIntervalMixin = { + componentWillMount: function() { + this.intervals = []; + }, + setInterval: function() { + this.intervals.push(setInterval.apply(null, arguments)); + }, + componentWillUnmount: function() { + this.intervals.map(clearInterval); + } +}; + +var TickTock = React.createClass({ + mixins: [SetIntervalMixin], // Use the mixin + getInitialState: function() { + return {seconds: 0}; + }, + componentDidMount: function() { + this.setInterval(this.tick, 1000); // Call a method on the mixin + }, + tick: function() { + this.setState({seconds: this.state.seconds + 1}); + }, + render: function() { + return ( +

+ React has been running for {this.state.seconds} seconds. +

+ ); + } +}); + +React.renderComponent( + , + document.getElementById('example') +); +``` + +A nice feature of mixins is that if a component is using multiple mixins and several mixins define the same lifecycle method (i.e. several mixins want to do some cleanup when the component is destroyed), all of the lifecycle methods are guaranteed to be called. + +## Testing + +**TODO: benjamn** + diff --git a/docs/refactor/06-forms.md b/docs/refactor/06-forms.md new file mode 100644 index 00000000..bab8cf94 --- /dev/null +++ b/docs/refactor/06-forms.md @@ -0,0 +1,119 @@ +# Forms + +Form components such as ``, ` +``` + +For HTML, this easily allows developers to supply multiline values. However, since React is JavaScript, we do not have string limitations and can use `\n` if we want newlines. In a world where we have `value` and `defaultValue`, it is ambiguous what role children play. For this reason, you should not use children when setting `