Description
Props and State are the two methods available to React to deal with immutable and mutable data within the application. This lesson will explain their uses and differences.
Component Props and State
- Dynamic data that Components use fall into one of two categories
-
Props:
- Similar to arguments of a function
- Are immutable once passed in
- Can be passed down to children explicitely
-
State:
- Private data held within the Component
-
Can be updated using
setState({someNew: 'data'})
or the updater fromuseState
- Must be updated from the object that owns it
- Can be passed down to children as Props
- Can be updated by children by passing functions
Stateless Functional Components
- At their most basic form Components are a lot like functions
- They accept input from their props and return HTML snippets as React Elements
- Any function that accepts one argument (props) and returns JSX is valid
- Stateless functions traditionally have no state of their own
<body>
<div id="root"/>
</body>
<script>
/* This is a perfectly valid React Component*/
const HelloThere = (props) => {
return <h1>Hello, { props.name }</h1>
}
ReactDom.render(<HelloThere name="Grace Hopper"/>,
document.getElementById('root')
)
</script>
<body>
<div id="root">
<!-- This is what the code would result in -->
<h1>Hello, Grace Hopper</h1>
</div>
</body>
All Props are Immutable
- Neither Function nor Class components should mutate their Props
- React requires Components to be 'Pure' toward their Props
/* Always returns the same JSX for given inputs */
function UserInfo (props) {
return (
<div className="UserInfo">
<Avatar user={ props.user } />
<div className="UserInfo-name">
{ props.user.name }
</div>
</div>
);
}
Pure and Impure Functions
- 'Pure' functions don't mutate inputs and always return the same output for the same inputs
/* This is a 'Pure' function */
/* It always returns the same output for given inputs */
function sum (first, second) {
return first + second;
}
/* This is an 'Impure' function */
/* It can return different things based on the balance */
function deduct (bankAccount, amount) {
bankAccount.balance = bankAccount.balance - amount;
return bankAccount
}
Component State
Description
- Data managed by the component that changes over time
- Considered private data by default
- Cannot be changed by the Parent
- Has a set default value, can be
null
- Plain JavaScript Object
Rules
- Never mutate the State directly
- Always use
this.setState()
or the updater fromuseState
- Limit access to State from children
- If building from a prior value, pass an update callback function to
this.setState()
State - Tick Live
- Rememeber the Ticking Clock example
See the Pen React Clock Example by Joshua Burke (@Dangeranger) on CodePen.
State - Tick Code
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(tick, 1000);
State - Extract Component
Does this use component state?
/* Now we have a component */
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
/* Use the component in a function */
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
State - Convert to Class
- Convert the stateless function to a Class
/* From this */
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
/* To this */
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
State - Start the Clock
class Clock extends React.Component {
constructor(props) {
/* Make sure to call super in a constructor */
super(props);
/* Setting the initial state */
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<!-- Use the state instead of props -->
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
State - Manage the Clock
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
State - Working Clock
See the Pen Hello World in React by Joshua Burke (@Dangeranger) on CodePen.
State - Remember
- Never update state directly, use
setState({some: 'state'})
/* Not good */
this.state.comment = 'Hello';
/* Excellent */
this.setState({comment: 'Hello'});
Lab: Color Clicker
Let's create a new react project that has a button you can click to change the color of some text.
- Create a new React component using
npx create-react-app
- Change your App component from a stateless functional component into a stateful class based component
- Render a header with blue text, and a button that says "Change Color"
- Using the state make it so that when you click the button the text changes to red
- When you click the button again the text should change back to blue
State - Updates can be Async
- Calling
setState()
schedules an update - React may batch those updates together for performance
- If you use a prior value to calculate the state, pass a callback function
/* Incorrect */
this.setState({
counter: this.state.counter + this.props.increment,
});
/* Super Great */
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
State - Updates are Merged
- When state has many properties, update each separately
- This allows for independent property merges
- The merge is shallow
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
State - Many Clocks
See the Pen Hello World in React by Joshua Burke (@Dangeranger) on CodePen.
Using Functional Component Syntax
Instead of creating a Component by extending the Component class we can write a function like this:
function StatelessComponent (props) {
return <h1>Hello {props.name}</h1>
}
Then we can slot it into a stateful component like so:
class Stateful extends React.Component {
constructor(props) {
super(props);
this.state = {name: "Bill"};
}
render() {
return (
<div>
<StatelessComponent name={this.state.name} />
</div>
);
}
}
We could also slot it into another stateless component and pass props directly to it:
function AlsoStateless (props) {
return (
<div>
<StatelessComponent name="Bob" />
</div>
)
}
Labs
- Component Props and State
- Stateless Functional Components
- All Props are Immutable
- Pure and Impure Functions
- Component State
- State - Tick Live
- State - Tick Code
- State - Extract Component
- State - Convert to Class
- State - Start the Clock
- State - Manage the Clock
- State - Working Clock
- State - Remember
- Lab: Color Clicker
- State - Updates can be Async
- State - Updates are Merged
- State - Many Clocks
- Using Functional Component Syntax
- Labs