Web applications are only interesting when they are dynamic. Any UI library will always provide a way to pass data around the system and React's idea is via the props and state.
React
We are going to cover following topics:
var container1 = document.getElementById('container-1');
function SayHelloToJohn() {
const name = 'John Doe';
return <h3>Hello Mr.{name} !!</h3>
}
class SayHiToJohn extends React.Component {
render() {
const name = 'John Doe';
return <h3>Hi Mr.{name} !!</h3>
}
}
ReactDOM.render(<div>
<SayHelloToJohn />
<SayHiToJohn />
</div>, container1);
These components only wish John. What if we want to wish another person? We can create a similar components with different names, but the disadvantage is we end up writing same template again and again with only name change. It's not the way things work, there should be a way to pass data dynamically to components. React way of passing data around your application is using Props and State.
Props
Props is simply data passed to components. Components allow us to pass data via attributes. For Functional components they can be accessed through function parameter props
and for Class components they can be accessed through this.props
Lets convert Components SayHelloToJohn
and SayHiToJohn
more generic and reusable components.
var container2 = document.getElementById('container-2');
function SayHello(props) {
return <h3>Hello Mr.{props.name} !!</h3>
}
class SayHi extends React.Component {
render() {
return <h3>Hi Mr.{this.props.name} !!</h3>
}
}
ReactDOM.render(
<div>
<SayHello name="John Doe" />
<SayHi name="John Doe" />
</div>, container2);
Finally, we are able to send names to components. Still our component wishes only one gender not everyone its not good. How do we overcome this situation, no issues, let's enhance our components to take more data to determine whether to wish male or female.
var container3 = document.getElementById('container-3');
function SayHello(props) {
if(props.gender === 'male') {
return <h3>Hello Mr.{props.name} !!</h3>
}
return <h3>Hello Miss.{props.name} !!</h3>
}
class SayHi extends React.Component {
render() {
if(props.gender === 'male') {
return <h3>Hello Mr.{this.props.name} !!</h3>
}
return <h3>Hello Ms.{this.props.name} !!</h3>
}
}
let App1 = () => {
return (
<div>
<SayHello name="John Doe" gender="male"/>
<SayHi name="Mary" gender="female"/>
</div>
)
}
ReactDOM.render(<App1 /> , container3);
Excellent our components improved, they are very dynamic and able to wish based on gender.
Default Props
We can give default props to the component. If props are provided to component they will be overridden, otherwise default props are used.
var container4 = document.getElementById('container-4');
const ColorButton = (props) => {
const styles = {
backgroundColor: props.bgColor,
color: props.txtColor
}
return <div className="btn" style={styles}>{props.title}</div>
}
ColorButton.defaultProps = {
bgColor: 'black',
txtColor: 'white',
title: 'Default Button styles applied'
};
ReactDOM.render(<div>
<ColorButton /><br /><br />
<ColorButton bgColor="green" title="Default Props are Overidden"/>
</div>, container4)
You can also define defaultProps using ES6 static keyword.
static defaultProps = {
bgColor: 'black',
txtColor: 'white',
title: 'Default Button styles applied'
}
Communication between Components
By now we can tell that components are completely independent and self-contained. The components just expect input and simply work anywhere in the application. If an application is developed using reactjs it would be a just hierarchy of components and they should communicate each other to make sure the application works without any issues.
There are three ways in which components can communicate each other
Parent to Child
This is the most common and can be seen everywhere. Parent components communicate with child using Props
.
You have already seen examples how we use Props
to send data into a component.
Let's see an example.
var container5 = document.getElementById('container-5');
const Father = () => {
const children = [
{name: 'John', school: 'ABC', country: 'India'},
{name: 'Mary', school: 'XYZ', country: 'India'},
{name: 'Robert', school: 'PQR', country: 'India'}
];
return (
<div>
{
children.map((info, index) => {
return <Child fromFather={info} />
})
}
</div>
)
}
const Child = (props) => {
const {fromFather} = props;
return (
<div className="well">
<p>My Name is {fromFather.name}. I stay with my parents at {fromFather.country} and I go to {fromFather.school} school</p>
</div>
)
}
ReactDOM.render(<Father />, container5);
So far good, Father gave everything to his children without asking.
Child to Parent
One of the child wants money to buy chocolates since he is just a child he will not have money, he will ask his father for some money to buy chocolates i.e. child will communicate with his father to get money.
If anything is required to child components from its parent. They use callbacks provided by parent components to get what they want.
var container6 = document.getElementById('container-6');
class Father extends React.Component {
constructor(props) {
super(props);
this.state = {
children: [
{id: 1, name: 'John', school: 'ABC', country: 'India'},
{id: 2, name: 'Mary', school: 'XYZ', country: 'India'},
{id: 3, name: 'Robert', school: 'PQR', country: 'India'}
]
}
this.childCalling = this.childCalling.bind(this);
}
childCalling(id) {
const {children} = this.state;
for(let i=0; i<children.length; i++) {
if(children[i].id === id) {
children[i].money = (id*10) + '$';
break;
}
}
this.setState({
children
});
}
render() {
const {children} = this.state;
return (
<div>
{
children.map((info, index) => {
return <Child fromFather={info}
id={info.id} callFather={this.childCalling} key={index}/>
})
}
</div>
)
}
}
const Child = (props) => {
const {fromFather, callFather, id} = props;
const askFather = () => {
callFather(id);
}
return (
<div className="well">
<p>My Name is {fromFather.name}. I stay with my parents at {fromFather.country} and I go to {fromFather.school} school</p>
<div>
<button className="btn btn-default" onClick={askFather}>Ask Papa</button>
{fromFather.money && <p>Papa gave me 10$</p> }
</div>
</div>
)
}
ReactDOM.render(<Father />, container6);
Components with no relation
Though components are not related to each other or related but, they are very far way in hierarchy. We have to place external event system, so that they can communicate each other. In programming world it's very common to use Event systems. There are many event systems out there, but we are going to use one in particular called PubSub (Publish/Subscribe) system.
In this we just publish an event with some information and anyone who subscribed or listening for the event will recieve the data. We are going to use PubSubJs in our demonstration.
var container7 = document.getElementById('container-7');
class A extends React.Component {
constructor(props) {
super(props);
this.state = {
addColor: {
'color': 'black'
}
};
this.colorSubscriber = this.colorSubscriber.bind(this);
PubSub.subscribe('event_from_b', this.colorSubscriber);
}
colorSubscriber(msg, data) {
this.setState({
addColor: {
'color': this.state.addColor.color === 'black' ? 'red' : 'black'
}
});
}
render() {
return(
<div style={this.state.addColor} className="container">This is Component A !!</div>
)
}
}
const B = () => {
const publish = () => {
PubSub.publish( 'event_from_b', 'hello world!' );
}
return (
<div className="btn btn-default" onClick={publish}>Click me to toggle color of component A</div>
)
}
const C = () => {
return(
<div>
<A />
<B />
</div>
)
}
ReactDOM.render(<C />, container7);
Let's see whats happening.
1) There is a component 'A' which has an internal state of style 'color' which paints component A.
2) There is a colorSubscriber
function which changes the internal state of style 'color' alternatively based on present color.
3) In constructor there is a subscriber
for event called event_from_b
and callback supplied is colorSubscriber. It means whenever an event_from_b
is published it's going to trigger all the subscribers and execute the callbacks passed to them.
4) There is a component 'B' which onClick is publishing an event called event_from_b
.
5) Finally there is a component 'C' which has both component 'A' and 'B'. But the component A and B are not related to each other in any way. 'A' and 'B' are completely two different components yet they are communicating using event system called PubSub.
This is just a sample to demonstrate how event system works. In the real world, we are not going to use PubSubJs. There are many libraries out there which implemented event systems in a better way which would help us to build applications. One such library is Redux. It is build using event system called Subscribe/Dispatch
. Redux comes with a store which has a dispatcher, subscriber, and state. Dispatcher and Subscriber are responsible for updating state. Redux is not dependent on Reactjs and can be implemented with any framework. React-Redux is the library that brings together react and redux. It provides some functions to access the state, dispatch and subscriber methods. This state is what is responsible for maintaining data for your application and is what is sent to components as props.
Components with no relations topic is inspired from a blog "How to communicate between ReactJS components" by Stéphane Derosiaux. He has explained everything beautifully. Go through the article its a great one.