DO's:
- Use explicit contracts to pipe data & events between systems
- Business rules should bubble towards the top, UI and semantics should sink towards the bottom
DONT's:
- Prescribe a single design pattern
- Use jQuery as a crutch
- Be a fundamentalist
- Only change state on the components that need to be re-rendered
- Use ref=<name> to access the component from the parent
- All components should be instantiated inside a render() call; avoid storing components in state
- Define a key for items in a list
Use ternary operator with null to conditionally render:
<div>{this.state.verified ? <i className="verified"/> : null}</div>
Use map to programmatically render children:
<ul> { _.map(this.state.items, function(item, index) { return <li key=index>{item}</li> }) }</ul>
Props: | represents the overall application state. |
---|---|
State: | represents the individual state of a component. |
Props: | configures how the application is to be rendered. |
State: | configures how the component is to be rendered. |
Where to use the methods:
setProps(): | can only be called on a root component. |
---|---|
setState(): | should only be called by the component itself. |
set<Name>(): | should be defined on a component that allows for its state to be modified externally. |
Example public set state method:
setValue: function(val) { this.setState({value:val}) }
Avoid direct API calls from components.
Use channels or event streams to pipe data into components
- Event streams: https://baconjs.github.io/
- Channels: https://github.com/postaljs/postal.js
componentWillMount(): | bind event stream to component state |
---|---|
componentWillUnmount(): | unbind component from an event stream |
Example Data Binding:
componentWillMount: function() { var self = this; this.site_sub = channel.subscribe("CRUD.site."+this.props.site_id, function(data) { self.setState({site: data.site}) }) }, componentWillUnmount: function() { if (this.site_sub) { this.site_sub.unsubscribe(); this.site_sub = null; } }
- Use on<event> properties to pipe events to functions that modify other components
- If a component modifies a component that is not in its refs, try to use a callback instead
Slug field example:
<input type="text" name="name" onChange={function() {self.refs.slug.setValue(event.target.value)}}/> <SlugField name="slug" ref="slug"/>