Intro to React
State
State in React
- Components are state machines
- A stateful component will declare its initial state, and then use the special, asynchronous this.setState to update state
- Why do you need to use this.setState? Because every time you do, React will update the view in that wonderful, efficient way that it does
- this.state, on its own, should be considered immutable
Virtual DOM
- Remember that React is like another API for the DOM - except it's very smart
- With React, you never interact directly with the DOM - only with React's virtual DOM
- Every time you use ReactDOM.render, React builds a DOM tree out of React Elements, similar to the actual DOM, and renders the view using its virtual DOM
Rendering
- When you use setState, React build a brand new virtual DOM tree
- React then diffs this tree with the old DOM tree, and makes the minimal adjustments necessary to render the updated view
- This is one of React's killer features - it's the reason why React renders so quickly!
React Principles
- Whenever possible, write stateless components
- A higher-level, stateful component will pass down its state as props to its children
- This lets props be the source of truth for those components
- State should be minimal
- State should contain data that a component's event handlers may change to trigger a UI update
- State should not contain computed data, other React components, or duplicated data from props
/* Using createClass */
const Heart = React.createClass({
getInitialState: function () {
return { hearted: false };
},
heart: function () {
this.setState({ hearted: true });
},
render: function () {
return <i className="fa fa-heart" onClick={this.heart}></i>
}
});
I Heart React
/* Using classes */
class Heart extends React.Component {
constructor (props) {
super(props);
this.state = { hearted: false };
}
heart () {
this.setState({ hearted: true });
}
render () {
return <i className="fa fa-heart" onClick={this.heart}></i>
}
});
I Heart ES6
Async
Lifecycle
- This is all well and good, but you might be wondering how we get state to hold data from an AJAX request
- In Angular, we have resolve blocks
- React does not have an equivalent. The React team recommends making AJAX requests from the ComponentDidMount lifecycle hook
- This is a lifecycle hook provided by react to run once the component mounts
- Note that the render method will still be invoked before it has data from your AJAX call
Simple AJAX
class Posts extends React.Component {
constructor (props) {
super(props);
this.state = { posts:[] };
}
componentDidMount () {
axios.get('/api/posts')
.then(res => res.data)
.then(data => this.setState({
posts: data
});
}
render () {
return (
<div>
{
this.state.posts.map(post => {
return <h1>{post.content}</h1>
});
}
</div>
);
}
});
What gives?
- There's also a lifecycle hook called ComponentWillMount, which executes before the component renders...that seems better for AJAX, right?
- Maybe not...ComponentWillMount runs on the server, if you're doing server-side rendering, but ComponentWillUnmount doesn't
- Memory leaks, separation of concerns, weird async bugs, etc.
- Maybe not...ComponentWillMount runs on the server, if you're doing server-side rendering, but ComponentWillUnmount doesn't
- That being said, ideas like Flux have different solutions (which we'll not cover here just yet). TLDR: ComponentDidMount !== Resolve
Resources
- https://facebook.github.io/react/index.html
- http://stackoverflow.com/questions/27139366/why-do-the-react-docs-recommend-doing-ajax-in-componentdidmount-not-componentwi
Intro to React - State
By Tom Kelly
Intro to React - State
- 1,292