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.
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.
clickHandler(){
console.log("clicking");
}
render() {
console.log("rendering");
return (
<div className="item">
<button onClick={()=>{this.clickHandler()}}>YAY</button>
</div>
);
}
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.
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')
);
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')
);
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>
);
}
}
//initialize the component
constructor(){
super()
console.log("constructing");
this.state = {
counter : 0
}
}
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.
Build the counter display into it's own component.
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.