|
| 1 | +# Component Specification |
| 2 | + |
| 3 | +A component specification is a plain JavaScript object that declaratively specifies the behavior of a component class. This object is passed to `createClass`, which in turn builds a `ReduxComponent` matching the spec. |
| 4 | + |
| 5 | +Generally speaking, any function assigned to a key on the specification object will be copied into the prototype of the class and thus become available as instance methods. The exception to this rule is for certain specially-named keys which are used by redux-components to implement core component behavior. The special keys are as follows: |
| 6 | + |
| 7 | +## Meta properties |
| 8 | + |
| 9 | +### spec.displayName |
| 10 | +```coffeescript |
| 11 | +spec.displayName = string |
| 12 | +``` |
| 13 | +If specified, gives a name to this component that can be used by debugging and development tools. |
| 14 | + |
| 15 | +> Just as with React, relying on displayName to do type checking in production is an antipattern. Use the instanceof operator. |
| 16 | +
|
| 17 | +### spec.statics |
| 18 | +```coffeescript |
| 19 | +spec.statics = { ... } |
| 20 | +``` |
| 21 | +All keys and values from ```spec.statics``` are merged onto the constructor for the component class via ```Object.assign```. This makes them available as "static methods" on the class constructor. |
| 22 | + |
| 23 | +### spec.mixins |
| 24 | +```coffeescript |
| 25 | +spec.mixins = [ {spec}, {spec}, ... ] |
| 26 | +``` |
| 27 | +An array of additional specs that will be mixed into this spec before creating the class. Mixins are processed in the order they appear in the array. In general, the keys on the mixin specs will be assigned to the base spec as with ```Object.assign```, with auto-binding for functions. There is special behavior for certain keys. See [Mixins](Mixins.md) for more. |
| 28 | + |
| 29 | +## Lifecycle methods |
| 30 | + |
| 31 | +### spec.componentWillMount |
| 32 | +```coffeescript |
| 33 | +spec.componentWillMount = => |
| 34 | +``` |
| 35 | +### spec.componentDidMount |
| 36 | +```coffeescript |
| 37 | +spec.componentDidMount = => |
| 38 | +``` |
| 39 | +### spec.componentWillUnmount |
| 40 | +```coffeescript |
| 41 | +spec.componentWillUnmount = => |
| 42 | +``` |
| 43 | +Specifies the lifecycle methods for instances of the class. See [Components](Components.md) for details on when the methods are called. |
| 44 | + |
| 45 | +## Redux-related properties |
| 46 | + |
| 47 | +### spec.getReducer |
| 48 | +```coffeescript |
| 49 | +spec.getReducer = => (state, action) => nextState |
| 50 | +``` |
| 51 | +getReducer returns a reducer function that will be used for the state subtree managed by this component. |
| 52 | + |
| 53 | +Reducers made by getReducer are automatically bound to their component instances so that they can have access to scoped properties, particularly scoped action verbs. |
| 54 | + |
| 55 | +> **NB:** |
| 56 | +> - After all mixins are evaluated, a final spec must have exactly one ```.getReducer```. We prefer to be unopinionated, so by default, there is no specified behavior for composing multiple reducers. (But see ```SubtreeMixin```.) |
| 57 | +
|
| 58 | +> - Do not use magic binding as an excuse to introduce impure behavior into your reducer! If you want the all the benefits of Redux, keep your reducers as pure functions of props and state. Don't make your reducer rely on non-constant properties of the redux-component, and don't be tempted to store any state on the redux-component itself. (You can sometimes use ```getReducer``` to mimic "impure" behaviors without making your reducer itself impure.) |
| 59 | +
|
| 60 | +> - By default, redux-components will call `getReducer()` only once when your component is mounted to a state tree. If you expect your reducer to change during the Redux store's lifecycle, you must arrange for `getReducer()` to be called at appropriate times, and for `Store.replaceReducer()` to be called on your root store. If you use redux-components and `SubtreeMixin` throughout your state tree, we provide facilities for automating this. |
| 61 | +
|
| 62 | +> - You may optionally declare a `getReducer` method that accepts a `stateNow` argument: |
| 63 | +```coffeescript |
| 64 | +spec.getReducer = (stateNow) => (state, action) => nextState |
| 65 | +``` |
| 66 | +> If you do, your reducer is considered to be a [dynamic reducer](/docs/Advanced/DynamicReducer.md). The JavaScript `Function.length` property is used to make this determination. Dynamic reducers are an advanced feature and should not generally be used. Please read [the dynamic reducer documentation](/docs/Advanced/DynamicReducer.md) carefully before use. |
| 67 | +
|
| 68 | +### spec.verbs |
| 69 | +```coffeescript |
| 70 | +spec.verbs = [ string, string, ... ] |
| 71 | +``` |
| 72 | +Specifies a list of action names that will be scoped to each instance of the component using the instance's path in the state tree. Verbs are scoped according to the following pattern: ```#{path}:#{verb}``` and are available on the instance object at a key corresponding to the verb root. For example, a component instance mounted at ```foo.bar``` in the state tree having a verb ```"BAZ"``` would have the scoped verb ```"foo.bar:BAZ"``` available as ```this.BAZ```. |
| 73 | + |
| 74 | +> If you don't want a verb to be scoped, don't put it in the verbs array. Instead set it as a plain string property on the specification. It will then bypass the auto-scoping behavior. |
| 75 | +
|
| 76 | +### spec.actionCreators |
| 77 | +```coffeescript |
| 78 | +spec.actionCreators = { key: (args...) -> action, ... } |
| 79 | +``` |
| 80 | +Specify the action creators associated with this component class. Each property on the ```actionCreators``` object will be bound to each component instance and made available on the instance as a method. |
| 81 | +> **NB:** The redux-components core makes no assumptions about which middleware is present on a store. If you have e.g. `redux-thunk` middleware installed, you may of course return thunks from your actions and actionCreators. |
| 82 | +
|
| 83 | +### spec.actionDispatchers |
| 84 | +```coffeescript |
| 85 | +spec.actionDispatchers = { key: (args...) -> action, ... } |
| 86 | +``` |
| 87 | +Specify action dispatchers associated with this component class. Action dispatchers are like action creators, except the value returned is automatically `dispatch()`ed to the Store where this component is mounted. The wrapped action function will return the same thing as `dispatch()`, allowing it to be used with thunks and other related middleware. |
| 88 | + |
| 89 | +### spec.selectors |
| 90 | +```coffeescript |
| 91 | +spec.selectors = { key: (state, ...) -> any, ... } |
| 92 | +``` |
| 93 | +Specify the selectors associated with this component class. Each property on the `selectors` object will be bound to each component instance and wrapped in a function that scopes the selector to the instance's state. The net effect will be that the state argument received by the selector will point to the state subtree managed by the particular component instance, rather than the global Redux state. |
| 94 | +> If you don't want a selector to be auto-scoped, don't put it in the selectors object. Instead set it as a property on the specification. This will bypass the auto-scoping behavior. |
| 95 | +
|
| 96 | +## Other properties |
| 97 | + |
| 98 | +The specification's other properties will be `Object.assign()`ed onto the prototype for the class. Properties that are functions will be automatically bound to class instances by the constructor. Other properties will be available on the prototype. |
0 commit comments