Ai Santos

@asantos3026

Data Flow in ReactJS

Second installment of my series for junior developers. About me, I come from a non-traditional Computer Science background, am an activist and advocate fighting for diversity and inclusion in the technology space. I blog about technical topics related to JavaScript, ReactJS and tech inclusion.

This week I’m writing about data flow in the React eco-system. Before explaining and implementing, we need to know some terms:

Props — are pieces of data that you can pass to Presentational Components. Typically, these are the children of Container Components. This one way data flow (top to bottom / parent to child) is a main tenet in ReactJS programming. As this data is passed, it does not change.

State — stores data that can change. We can read and write to state. This object comes from Redux or stateful components.

As in most of the JavaScript ecosystem, there are multiple ways to implement. I will show you three different ways to display data in your Presentational Component.

One way is to pass it as a default prop:

import React, { Component } from 'react';
class Address extends Component {
render () {
return (
<div>
<img src={this.props.imgUrl} />
<h4>{this.props.streetLineOne}</h4>
<h4>{this.props.streetLineTwo}</h4>
<h4>{this.props.state}</h4>
<h4>{this.props.zip}</h4>
</div>
);
}
}
Address.defaultProps = {
imgUrl: '/images/icons/map_marker.svg',
streetLineOne: '1234 This Way Street',
streetLineTwo: 'Apt. 1',
state: 'CA',
zip: 94703,
}
export default Address

Another, is to pass props via the Parent Component

Step 1: Build the child component that will receive props from its parent. Mini-steps involved in this process: import React built ins, map your data in the JSX code you are returning, check what type of data each prop returns, and finally export your child component.

import React built ins

import React from 'react';
import PropTypes from 'prop-types';

map your data in the JSX code you are returning

const Address = (props) => {
return (
{props.showIcon &&
<img className={ props.iconClassName }
src="/images/icons/map_marker.svg" />
}
<address>
<div>
<span itemProp="streetAdress">{props.location}</span>
</div>
<div>
<span itemProp="addressLocality">
{props.location.city},
</span>
<span itemProp="addressRegion">
{props.location.state}
</span>
<span itemProp="postalCode">
{props.location.zipCode}
</span>
</div>
</address>
);
}

The code above may seem dense at first, upon breakdown it is pretty simple. There are 3 React components inside of <Address />

  1. The image component, which is only shown when the boolean showIcon returns true .
  2. A divthat contains the street address in props.location
  3. Another div that contains the locality of the location in props.location.city props.location.state props.location.zipCode

So the <Address /> component is expecting a location property. So where is the props object coming from? As you will see, this data object is being passed down from its’ parent <LocationInfoCard /> .

check what type of data each prop returns

Address.propTypes = {
location: PropTypes.object.isRequired,
showIcon: PropTypes.bool,
iconClassName: PropTypes.string,
};

export your newly built child component

export default Address;

Step 2: Build its Parent Component. Mini-steps involved: import root style sheet, CSS tools, declare your new parent component and pass down to it the data you want to display via props, export your new parent component.

import React built ins, style sheets and CSS tools

import React from 'react';
import withStyles from '../../../core/isomorphic-style-loader/withStyles';
import s from './LocationInfoCard.scss';
import Address from '../../Location/Address';
import Phone from '../../Location/Phone';

declare your new parent component and pass down to it the data you want to display via props.

const LocationInfoCard = (props) => {
const { location } = props //location is a key in the props object
return (
<div>
<Phone
location={ location }
iconClassName={ s.phoneIcon }
/>
<Address
location={ location }
showIcon
iconClassName={ s.mapMarkerIcon}
/>
</div>
);
}

export your new parent component

export default withStyles(s)(LocationInfoCard)

Our props / data object is now dynamically being piped in to <LocationInfoCard /> . We will see in the last example how this parent component is getting this object.

The <LocationInfoCard /> is a stateless functional component. The props object parameter it receives has a key inside it called location . We can access locationvia object destructuring which will help us write shorter syntax. Here is a clear explanation from the Mozilla documentation.

var myObj = {p: 42, q: true};
var {p, q} = myObj;
console.log(p) = 42

In the case above, we can write p instead of myObj.p . Similarly, in props.location , we can now access this same property by using just its key,location .

Inside of <LocationInfoCard /> there are 2 custom components: <Phone /> and <Address /> . It may seem confusing that we are only passing the location prop but remember, we mapped those data object properties when we wrote the child component, <Address /> , even though I did not show you the example, you can imagine that the same applies to <Phone />

Last but not least, the third example I’m going to show you is how props are passed down using a data store like Redux.

react-redux

In the infographic above, we can see the unidirectional data flow that is the bread and butter of React applications. To keep it simple, high level and to solidify understanding of data flow in React, we are going to focus on the process highlighted by the red box.

Step 1: Connect your Container Component to Redux

npm install --save react-redux

We are going to need a function called connect . React-redux allows us to connect our React application to Redux which will then allow us to connect to Redux’s data store where we can access state .

State — means inputs that are being tracked and can be changed*. Some examples of state changes are variable reassignment, and user interactions (clicks, submitting forms, mouse moves — events).

import React from 'react';
import { connect } from 'react-redux';

Typically you have to create actions and reducers. In our app, let’s assume this has already been built out for us to so we can understand in bite size pieces how data flows in React.

Step 2: Import the component that is going to receive the location prop.

import LocationInfoCard from './LocationInfoCard';

Step 3: Declare your mapStateToProps function (see definition by ReduxJS documentation below)

To use connect(), you need to define a special function called mapStateToProps that tells how to transform the current Redux store state into the props you want to pass to a presentational component you are wrapping.
const mapStateToProps = state => ({
location: state.location,
});

Here we can see that the mapStateToProps function is creating a new object that has a property called location which we are then passing to <LocationInfoCard />

export const locationInfoCard = {
path: '/location-info',
action: () => {
const ConnectedLocationInfoCard =
connect(mapStateToProps(LocationInfoCard);
return {
component: (
<ConnectedLocationInfoCard route="location-info" />
),
};
},
};

Don’t feel overwhelmed by the dense code above. We’ll take it line by line to understand what is happening. We can see that a new constant called locationInfoCard is being exported using ES6 syntax.

This constant contains an object that has a property called path and a method called action. /location-info is where we will see the child components of <LocationInfoCard /> displayed.

What’s more interesting is theaction method. This is the heart of our newly connected container component. mapStateToProps takes LocationInfoCard as an argument and returns a new route component. Now, when we go to this route, we will be able to access our application’s state and along with that its properties.

To recap, I showed you 3 ways to pipe in data to your React component:

  1. Pass data in using default props
  2. Pass data down from parent to child components
  3. Map state to props using react-redux

Hope my explanations were helpful. Feel free to reach out to me via comments.

More by Ai Santos

Topics of interest

More Related Stories