- Pass in data to a React component via
props
. - Modify the
state
of a React component through events.
Before, we learned that React is a powerful and efficient front-end framework that emphasized performance and reusability of components, and that it utilizes JSX for these components. This is what we had for our Hello
component:
// bring in React and Component instance from react
import React, {Component} from 'react'
// define our Hello component
class Hello extends Component {
// what should the component render
render () {
// Make sure to return some UI
return (
<h1>Hello World!</h1>
)
}
}
export default Hello
Now we'll see what we can do to make this more practical, and introduce the React concepts of props
and state
.
Our Hello
component isn't too helpful. Let's make it more interesting.
- Rather than simply display "Hello world", let's display a greeting to the user.
- So the question is, how do we feed a name to our
Hello
component without hardcoding it into our render method?
First, we pass in data wherever we are rendering our component, in this case in src/index.js
:
import ReactDOM from `react-dom`
import Hello from './App.js'
ReactDOM.render(
<Hello name={"Nick"} />,
document.getElementById('root')
)
Then in our component definition, we have a reference to that data via as a property on the props
object...
class Hello extends Component {
render () {
return (
<h1>Hello {this.props.name}</h1>
)
}
}
In the above example, we replaced world
with {this.props.name}
.
Properties! Every component has .props
- Properties are immutable. That is, they cannot be changed while your program is running.
- We define properties in development and pass them in as attributes to the JSX element in our
.render
method.
First we can pass multiple properties to our component when its rendered in src/index.js
..
import ReactDOM from `react-dom`
import Hello from './App.js'
ReactDOM.render(
<Hello name={"Nick"} age={24} />,
document.getElementById('root')
)
Then in our component definition we have access to both values...
class Hello extends Component {
render () {
return (
<div>
<h1>Hello {this.props.name}</h1>
<p>You are {this.props.age} years old</p>
<div>
)
}
}
NOTE: The return statement in
render
can only return one DOM element. You can, however, place multiple elements within a parent DOM element, like we do in the previous example with<div>
.
So we know about React properties, and how they relate to our component's data.
- The thing is,
props
represent data that will be the same every time our component is rendered. What about data in our application that may change depending on user action? - That's where
state
comes in...
Values stored in a component's state are mutable attributes.
- Like properties, we can access state values using
this.state.val
- Setting up and modifying state is not as straightforward as properties. It involves explicitly declaring the mutation, and then defining methods to define how to update our state....
Lets implement state in our earlier Hello
example by incorporating a counter into our greeting.
class Hello extends Component {
// when our component is initialized,
// our constructor function is called
constructor (props) {
// make call to parent class' (Component) constructor
super()
// define an initial state
this.state = {
counter: 0 // initialize this.state.counter to be 0
}
}
render () {
return (
<div>
<h1>Hello {this.props.name}</h1>
<p>You are {this.props.age} years old</p>
<p>The initial count is {this.state.counter}
</p>
</div>
)
}
}
Ok, we set an initial state. But in order to change the state, we need to set up some sort of trigger event.
Let's do that via a button click event. Where do you think should we initialize that button click event?
Inside the
JSX
of our return value! In Hellorender
method we can instantiate our event listeners. Notice the ultra-slick ES6 function.
class Hello extends Component {
constructor (props) {
super()
this.state = {
counter: 0
}
}
handleClick (e) {
// setState is inherited from the Component class
this.setState({
counter: this.state.counter + 1
})
}
render () {
// can only return one top-level element
return (
<div>
<h1>Hello {this.props.name}</h1>
<p>You are {this.props.age} years old</p>
<p>The initial count is {this.state.counter}
</p>
<button onClick={(e) => this.handleClick(e)}>click me!</button>
</div>
)
}
}
Take a closer look at how this event is implemented. We use an attribute called
onClick
to define the behavior as to what happens when we click this particular button. As it's value, we're passing in an anonymous function that invokes handleClick, a function defined on this component.
Whenever we run .setState
, our component does a "diff", comparing the Virtual DOM node with the updated state to the current DOM. It only replaces the current DOM with parts that have changed.
React, like Angular, is a powerful web framework that allows fast rendering and is a front-end tool. It works mainly in the "views" layer. It is meant to maintain readability, reusability, and performance.