diff --git a/ghdocs/BESTPRACTICES.md b/ghdocs/BESTPRACTICES.md
index 130a90ef9c836..c04dd9aeffdcd 100644
--- a/ghdocs/BESTPRACTICES.md
+++ b/ghdocs/BESTPRACTICES.md
@@ -23,6 +23,138 @@ interface IButton {
}
```
+## Use @autobind. Avoid ALL binds in templates
+
+The autobind decorator simplifies making event callbacks "bound" to the instance. It's easy to use:
+
+```typescript
+class Foo {
+
+ @autobind
+ public _onClick(ev: React.MouseEvent) {
+ }
+
+}
+```
+
+When we use bind in a template, it means that the function is recreated every time, which is an anti-pattern.
+
+## For gathering refs, avoid string refs, use resolve functions
+
+Facebook has deprecated the use of string refs. Plus, string refs don't play very well with some scenarios like in Layered content, where the content may be asynchronously rendered. The recommendation is to use functions to resolve refs. These functions must be pre-bound to
+
+Bad:
+```typescript
+public render() {
+ return
this._root = el } />
+}
+```
+
+Good:
+```typescript
+private _root: HTMLElement;
+private _resolveRoot: (element: HTMLElement) => any;
+
+constructor() {
+ this._resolveRoot = (el: HTMLElement) => this._root = el;
+}
+
+public render() {
+ return
+}
+```
+
+Note that it's very critical you do NOT inline the functions in render! This causes weird side effects, because the function
+is recreated. If you do this, react will call your function with null to clear it, and then render, and then once complete, will
+call it again with the element. This creates timing issues where your ref may be null when you didn't expect.
+
+See example here that illustates refs being re-evaluated:
+
+http://codepen.io/dzearing/pen/WGZOaR
+
+## Use unique keys for items in a mapped array, avoid indexes for keys
+
+```typescript
+public render() {
+ return (
+
+ { this.props.items.map((item, index)=> (
+
+
+
+ )) }
+
+ );
+}
+```
+
+When you need to map data, require that your data have unique ids available. When you map the data to content, use the id as
+the item's key. This helps React's dom diffing to understand which elements represent which items.
+
+When your code uses index as the key, this can cause unexpected side effects. For example, say that each component you map items to
+maintains some internal state, like the value in an uncontrolled input box. Removing an item in the array will not reset that state
+and react will think the first text box still represents key "0", which is actually now a different item, and thus will not re-render
+the component, leaving the old state intact.
+
+So lesson is, use actual unique ids for items that come from the data, rather than generated by the ux component, and thus require
+that your data has ids so that you can use that as a unique identifier for rendering.
+
+## Avoid nesting content in an array, wrap mapped content in component instead.
+
+When we do inline mapped entries, we want to inline the content in the map:
+
+Bad:
+```typescript
+class Foo extends React.Component {
+ public render() {
+ return (
+
+ );
+ }
+
+ @autobind
+ _onClick(ev: MouseEvent) {
+
+ }
+}
+```
+
## Extend from BaseComponent instead of React.Component in most cases.
In the common folder, there exists a BaseComponent class. For simple components, it may be unnecessary to use.
@@ -56,7 +188,208 @@ If specific component elements need special classnames injected, add more classN
A component's SCSS file should ONLY include files applicable to the component, and should not define styles for any other component.
-# Class name guidelines
+# Data/state management best practices
+
+## Things to flat out avoid
+
+Singletons and globals. Do not share state of a component via a singleton instance object. This is a pure anti-pattern for the following reasons:
+
+* Singletons have no lifetime and therefore can't initialize/clean up when they aren't used.
+* Singletons often paint you into a corner when you want more than one of the same thing on the page.
+* They are often difficult to test without polluting states required for other tests.
+* The make non-browser scenario reuse really difficult. (Build tooling, server side code.)
+
+Data and state should always follow the lifetime of the component that owns it. When that component is no longer needed, the state should
+be garbage collected, event handlers should be removed, and xhr requires spawned in that context should be cancelled.
+
+There are cases where everything should share a common instance of a store; Persona presence is a great example. We have solutions that enable the code within a component scope to access shared stores. See store usage section below.
+
+## Use const values global to a file, rather than as static members
+
+Don't use public/private statics, use file scope.
+
+Bad:
+```typescript
+class Foo {
+ private static DEFAULT_DELAY = 300;
+}
+```
+
+Good:
+```typescript
+const DEFAULT_DELAY = 300;
+
+class Foo {
+}
+```
+
+Note: using file scopes minimizes the name down to 1 character, whereas this.REALLY_LONG_NAME doesn't minify the name. Caveat being
+that if you export it, minify won't touch exports.
+
+## Use private members only for managing state local to a component that should not affect rendering when mutating
+
+Bad:
+```typescript
+class Foo extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ isMounted: false
+ };
+ }
+
+ componentDidMount() {
+ this.setState({
+ isMounted: true
+ });
+ }
+
+ render() {
+ return
+ }
+}
+```
+
+Basically privates should only be use for tracking this that in no way affect the frequency of render. In some cases, you many
+have an object which fires change events yet doesn't mutate, and you want to re-render on change events. In these cases, privates
+may be used to store the object reference.
+
+## Use component state only for managing local state that is private to a component that should trigger re-render on mutation
+
+Bad:
+```typescript
+class Foo extends React.Component {
+ private _fooRocks: boolean;
+
+ render() {
+ return
;
+ }
+
+ private _onClick() {
+ this.setState({
+ fooRocks: !this.state.fooRocks
+ });
+ }
+```
+
+## Experimental: Use a store for storing shared state within a component heirachy which must be shared across objects
+
+While React state management is very useful for simple, private state, it becomes unweildy when many things share that state
+and you start ending up with many owners of the same state value. In these cases it may drive you towards a flux solution, but
+before we jump there, lets call out a few things.
+
+* Global singletons are code smell, do not use globals or singletons except for very rare cases
+* Do not store complex shared state directly in the components, this is also code smell
+
+Instead, make a store and wire dumb components together the store.
+
+What is a store?
+
+Think of a store as a self aware observable; it maintains state, and provides read/write access to that state. When its state
+changes, it can emit change events causing components to re-evaluate.
+
+Here's an example store which tracks selection:
+
+```typescript
+class SimpleSelectionStore extends BaseStore {
+ private _selectedKey: string;
+
+ public isSelected(key: string) {
+ return key === this._selectedKey;
+ }
+
+ public setSelected(key: string) {
+ if (this._selectedKey !== key) {
+ this._selectedKey = key;
+ this.emitChange();
+ }
+ }
+}
+```
+
+While we do not want globals, we do want simplified access to the stores available in a given component scope.
+
+You can use the StoreHost component to host stores within any given scope:
+
+```typescript
+const stores = {
+ selection: new SimpleSelectionStore()
+};
+
+public render() {
+ return (
+
+
+
+ );
+}
+```
+
+You can write dumb components:
+
+```typescript
+const Item = (props) => (
+
{ `I am item ${ props.name } and I'm ${ props.isSelected ? 'selected' : 'unselected' }
+);
+```
+
+And you can use the `connect` function to create a ConnectedItem which wraps the dumb component and translates the props
+and stores in its context into props for the dumb component:
+
+```typescript
+export ConnectedItem = connect(Item, (stores, props) => ({
+ name: props.item.name,
+ isSelected: stores.selection.isSelected(props.item.key),
+ onClick: () => stores.selection.setSelected(props.item.key)
+}));
+```
+
+Now in this setup, your state is in one place, it is composable and can have lifetime, and your dumb ui has no understanding
+of the contextual stores provided.
+
+# CSS class name guidelines
TODO: include our class name guidelines.
diff --git a/package.json b/package.json
index 9c326b3c38f6e..323879390d497 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "office-ui-fabric-react",
- "version": "0.47.0",
+ "version": "0.48.0",
"description": "Reusable React components for building experiences for Office 365.",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
diff --git a/src/Utilities.ts b/src/Utilities.ts
index 9b00e246d1ff0..e95247a58fc45 100644
--- a/src/Utilities.ts
+++ b/src/Utilities.ts
@@ -2,3 +2,4 @@ export * from './common/BaseComponent';
export * from './utilities/css';
export * from './utilities/rtl';
export * from './utilities/hoist';
+export * from './utilities/autobind';
diff --git a/src/common/BaseComponent.test.ts b/src/common/BaseComponent.test.tsx
similarity index 74%
rename from src/common/BaseComponent.test.ts
rename to src/common/BaseComponent.test.tsx
index 91955bcbc6b38..7c647990d2a7a 100644
--- a/src/common/BaseComponent.test.ts
+++ b/src/common/BaseComponent.test.tsx
@@ -1,3 +1,11 @@
+/* tslint:disable:no-unused-variable */
+import * as React from 'react';
+/* tslint:enable:no-unused-variable */
+
+import * as ReactTestUtils from 'react-addons-test-utils';
+
+let { expect } = chai;
+
import { BaseComponent } from './BaseComponent';
let { assert } = chai;
@@ -54,6 +62,22 @@ describe('BaseComponent', () => {
_buildTestFor('render');
_buildTestFor('componentDidUpdate');
_buildTestFor('componentWillUnmount');
+
+ it('can resolve refs', () => {
+ class Foo extends BaseComponent<{}, {}> {
+ public root: HTMLElement;
+
+ public render() {
+ return ;
+ }
+ }
+
+ let component = ReactTestUtils.renderIntoDocument(
+
+ ) as any;
+
+ expect(component.root).to.exist;
+ });
});
function _buildTestFor(methodName) {
diff --git a/src/common/BaseComponent.ts b/src/common/BaseComponent.ts
index 3fc781cfabe49..6e7a5d86c8774 100644
--- a/src/common/BaseComponent.ts
+++ b/src/common/BaseComponent.ts
@@ -18,6 +18,7 @@ export class BaseComponent
{ items.map((item, index) => (
// If the item name is equal to '-', a divider will be generated.
item.name === '-' ? (
+ className={ css('ms-ContextualMenu-divider', item.className) }/>
) : (