React Render Timing / State
props / render function
So far we have been able to manipulate the dom, getting things to render based on data.
Now, we will dynamically render react components based on user action.
DOM Manipulation / State
In react the way to cause react to manipulate the dom is:
- put your data in a different object called
state
- when your user has made an action / your data has changed, call
this.setState
- this causes react to call the render function of the component again. the new
state
values are subsituted for the old ones.
Click Handlers
clickHandler(){
console.log("clicking");
}
render() {
console.log("rendering");
return (
<div className="item">
<button onClick={()=>{this.clickHandler()}}>YAY</button>
</div>
);
}
React State
Now we have a button that can be clicked.
Let's change some attribute of the class, a counter that gets incremented.
clickHandler(){
console.log("clicking", this.counter);
if( this.counter === undefined ){
this.counter = 1;
}else{
this.counter++;
}
}
render() {
console.log("rendering");
return (
<div className="item">
<button onClick={()=>{this.clickHandler()}}>YAY</button>
</div>
);
}
This code increments the value, but what happens when we try to output it?
<p>{this.counter}</p>
We can see that the class attribute gets incremented, but the screen doesn't change.
Dynamic React Rendering
class Item extends React.Component {
constructor(){
super();
console.log("constructor");
// set the default value
this.state = {
counter:0
};
}
// our click method
handleClick(){
var currentValue = this.state.counter + 1;
console.log("clicking", currentValue);
// set the state of this component
this.setState( { counter: currentValue } );
}
// what happens when the component renders
render() {
console.log("rendering");
return (
<div>
<span>{this.state.counter}</span>
<button onClick={()=>{this.handleClick()}}>click me!</button>
</div>
);
}
}
ReactDOM.render(
<Item />,
document.getElementById('root')
);
Static React Rendering
We pass data into a component using props.
class Banana extends React.Component {
render() {
return (
<div>
<p>count: {this.props.count}</p>
</div>
);
}
}
ReactDOM.render(
<Banana count={0}/>,
document.getElementById('root')
);
props
can never be altered inside the component
class Banana extends React.Component {
increment(){
// makes an error
this.props.counter++;
}
render() {
return (
<div>
<p onClick={()=>{this.increment()}}>count: {this.props.counter}</p>
</div>
);
}
}
ReactDOM.render(
<Banana counter={0}/>,
document.getElementById('root')
);
Re-rendering with props
If state
is passed into a component, it becomes props
.
<Count counter={this.state.counter} />
If we have a sub component that takes in a changing prop, that component also gets rerendered: Let's put our span inside it's own component:
<span>{this.state.counter}</span>
changes into:
<Count counter={this.state.counter}/>
When you pass new props to a component, it gets re-rendered.
class Count extends React.Component {
render() {
console.log("rendering count component");
return (
<div>
<span>{this.props.counter}</span>
</div>
);
}
}
Default Data
//initialize the component
constructor(){
super()
console.log("constructing");
this.state = {
counter : 0
}
}
Pairing Exercise
Clone the react repo into a named folder:
$ git clone https://github.com/wdi-sg/react-reference.git state
Check out the hot laoding branch:
$ git checkout 3-react-hotload
Build the above counter increment.
Watch the console to see when clicking and rendering happen.
Further
Build the counter display into it's own component.
Further
Make a second and third button that increments by 2 and 3. Send those props to the display component.
Display the current count and an array of previous values in the display component.