Components are used to separate concerns, not templates and display logic. When using React, you must embrace the idea that markup, and the code that generates it, are inherently tied together.
var MyComponent = React.createClass({
render: function() {
return React.createElement('h1', null, 'HelloWorld')
}
});
class MyComponent extends React.Component {
render() {
return React.createElement('h1', null, 'HelloWorld')
}
}
JSX -- an XML-like syntax for constructing markup within React components.
React.createElement('h1', { className: 'title'}, 'Hello World')
<h1 className="title">Hello World</h1>
render: function() {
return React.createElement('h1', { className: 'divider'},
"Label Text",
React.createElement('hr')
);
}
render: function() {
return <div className="divider">
Label Text<hr />
</div>;
}
Any dsl changes to React does not affect JSX
Seeing both the markup and code clearly separates concerns in the file.
Open Console
npm i reactjs-adventure -g
mkdir
<div className="divider">
<h2>FooBar</h2>
</div>
var Divider = React.createClass({
render: function() {
return (
<div className="divider">
<h2>FooBar</h2>
</div>
);
}
});
var Divider = React.createClass({
render: function() {
var text = 'FooBar';
return (
<div className="divider">
<h2>{text}</h2><hr />
</div>
);
}
});
<div id="some-id" className="some-class-name"></div>
dynamic
var recordId = this.props.id;
var classes = 'some-class-name';
...
<div id={recordId} className={classes}>...</div>
<div className={
this.state.isComplete ? 'isComplete' : ''
}>...</div>
use the &&
<div>
<input ref="myInput" ... />
</div>
this.ref.myInput // Inside your component
...
handleClick: function(event) { ... },
render: function() {
return <div onClick={this.handleClick.bind(this)}>...</div>
}
<div>
{/*
a comment
*/}
</div>
<input
/*
comment
*/
/>
<input
name="email" // inline comment
/>
<label htmlFor="for-text" ...>
<div className={classes} ...>
var styles = {
borderColor: '#999',
borderThickness: '1px'
};
React.render(<div style={styles}>...</div>, node);
var DividerClass = React.createClass({ displayName: 'Divider',
render: function() {
return {
React.createElement('div', {className: 'divider'},
React.createElement('h2', null, this.props.children),
React.createElement('hr', null)
)
}
}
})
called only once, sets default values when not specified by parent
called only once, chance to customize internal state
before the initial render, last chance to change the state before a render method is called.
Builds the virtual DOM - should be a PURE
function
can return null, false or React component
Can access actual node via this.getDOMNode()
This is the lifecycle hook for accessing non-react components
var datasources = [...];
var MyComponent = React.createClass({
render: function() {
return <input />
},
componentDidMount: function() {
$(this.getDOMNode()).autocomplete({
sources: datasources
})
}
});
Props can change at any moment, this method gives the component the opportunity to update the state from the changed props.
componentWillReceiveProps: function(nextProps) {
if(nextProps.checked !== undefined) {
this.setState({
checked: nextProps.checked
});
}
}
If you don't need to re-render the component return false.
** Be careful not to pre-optimize
Called when props change, but can't update date in this method.
similar to componentDidMount
this is where you can do any cleanup
calculated values as state
calcualate values at render time.
Short for Properties
var TableRow = React.createClass({ propTypes: { survey: React.PropTypes.shape({ id: React.PropTypes.number.isRequired }).isRequired, onClick: React.PropTypes.func } });
called as soon as React.createClass is called
Internal state of your component
<button className="btn btn-save"
onClick={this.handleSaveClicked}>
Save
</button>
Objects mixed in to our Components:
React.createClass({
mixins: [{
getInitialState: function() { return {a: 1}}
}],
getInitialState: function() { return { b: 2}}
});
Result: {a: 1, b: 2}
handleEvent: function(event) {
var DOMNode = event.target;
var newValue = DOMNode.value;
}
<textarea
value={this.state.mytext}
onChange={this.handleEvent} />
<select value="{this.state.selectValue" onChange={this.handleChange}>
<option value="A">A</option>
<option value="B">B</option>
</select>
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var TodoList = React.createClass({
getInitialState: function() {
return {items: ['hello', 'world', 'click', 'me']};
},
handleAdd: function() {
var newItems =
this.state.items.concat([prompt('Enter some text')]);
this.setState({items: newItems});
},
handleRemove: function(i) {
var newItems = this.state.items;
newItems.splice(i, 1);
this.setState({items: newItems});
},
render: function() {
var items = this.state.items.map(function(item, i) {
return (
<div key={item} onClick={this.handleRemove.bind(this, i)}>
{item}
</div>
);
}.bind(this));
return (
<div>
<button onClick={this.handleAdd}>Add Item</button>
<ReactCSSTransitionGroup transitionName="example">
{items}
</ReactCSSTransitionGroup>
</div>
);
}
});
var routes = (
<Route handler={App} path="/">
<DefaultRoute handler={Home} />
<Route name="about" handler={About} />
<Route name="users" handler={Users}>
<Route name="recent-users" path="recent" handler={RecentUsers} />
<Route name="user" path="/user/:userId" handler={User} />
<NotFoundRoute handler={UserRouteNotFound}/>
</Route>
<NotFoundRoute handler={NotFound}/>
<Redirect from="company" to="about" />
</Route>
);
Router.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
// Or, if you'd like to use the HTML5 history API for cleaner URLs:
Router.run(routes, Router.HistoryLocation, function (Handler) {
React.render(<Handler/>, document.body);
});
https://github.com/rackt/react-router/blob/master/docs/guides/overview.md
npm i reactjs-adventure
git clone https://github.com/twilson63/reactjs-example.git