Follow me on Twitter, happy to take your suggestions on topics or improvements /Chris
TLDR; Adding props, or properties to your component means we add attributes to our component element. This means we can pass data from an outer component to an inner component. That data can either be data that we want to render, or a function that we want to invoke.
In this chapter we will cover the following:
- Passing data, you will learn to pass data from the outside and render that in the component.
- Validate, we will learn to validate our input properties by using the library
PropTypes
You can select between class based or a functional component, when you want to just show data. Data is shown by returning JSX. Let's show both versions below.
-
Create a new project by running the command
git clone
:git clone https://github.com/softchris/react-starter-project demo-props cd demo-props
This starter project is based on the tutorial in Setup with Webpack.
-
Run
npm install
to install all dependencies:npm install
-
Create a file Product.js in the src directory and give it the following content:
import React from 'react'; class Product extends React.Component { render() { return ( <div>{this.props.data.name}</div> ); } } export default Product;
To use the component, you will need to import it into index.js and define data you can pass into the component.
-
Open index.js and add the following import statement:
import Product from './Product';
-
Next, add the following code, just after the import statements:
const product = { name: 'Game Console' };
-
Next, locate the part that looks like so:
ReactDOM.render( <div>{title}</div>, document.getElementById('app') );
and change it to the following code:
ReactDOM.render( <Product data={product}/>, document.getElementById('app') );
-
Try out the app by running
npm start
in the console:npm start
-
Navigate to http://localhost:8080 in a browser:
You should see the following output:
Game Console
The output comes from your
Product
component.Note how the
Product
element is now being rendered and thedata
property is assigned to with theproduct
object.In the above code you:
-
Passed input data. The
product
object was assigned to thedata
attribute. Note the use of{}
to pass in the data. It's needed if want to pass something in and you want React to interpret it. -
Rendered data. In the
render()
method you rendered the input data by returning it as JSX and by drilling down into it like so:this.props.data.name
thereby you accessed the passed in object and drilled down, to something you could render, the
name
attribute.
-
You can define it as a functional component instead of class component. To do so:
-
Open Product.js and change the content to the following:
import React from 'react'; const Product = (props) => <div>{props.data.name}</div> export default Product;
Webpack remcompiles the bundle as soon as you save the file.
-
Go to your existing browser and http://localhost:8080:
Game Console
It still works, great.
Like the class based component, there's a
props
involved. You need to drill intoprops
to find the attribute that your passed in data resides on.Props
is a parameter being passed into the function, that makes out your component.
When you rendered an object, you ended up returning JSX, JSX that was interpolated with input data. Rendering a list is similar, you still need to return JSX but you an use a function like map()
to iterate through your content.
-
Create the file Cart.js in the src directory and give it the following content:
import React from 'react'; import Product from './Product'; class Cart extends React.Component { render() { return ( <div>{this.props.data.map( product => <Product data={product} />)}</div> ); } } export default Cart;
In the above code, your return statement consist of a JSX expression that interpolates
this.props.products
using amap()
function, like so:{this.props.product.map( product => <Product data={product} />)}
For every item in
products
, a JSX statement is being produced. So what you end up with is a list of<Product>
elements. Note how eachproduct
instance binds to thedata
property on theProduct
component you created earlier. -
To use the
Cart
component. Add an import reference to index.js, like so:import Cart from './cart';
Next, define the data meant for the cart.
-
After the import statements, add the following code:
const products = [ { name: 'Game console' }, { name: 'Game' } ]
-
Locate the part of the code that says:
ReactDOM.render( <Product data={product}/>, document.getElementById('app') );
and change it to the following code:
ReactDOM.render( <Cart data={products}/>, document.getElementById('app') );
The app should recompile as soon as you save the file.
-
Navigate to http://localhost:8080:
You should see the following output:
Game console Game
Success, you've managed to render list content.
As our components becomes more and more complicated, we want to ensure we use them correctly. For example, if a component has a certain property set, it should render it. We might even go so far as to convey that if a property is not set you should throw an error. The library prop-types
helps you to define what properties are a must and helps us define what type they are.
The steps you need to take to use the library are:
- Download it, you can download it using npm or yarn.
- Import it, install it via npm or yarn.
- Configure. define the properties your component should have and what type they are.
-
Download the library by typing the following in a console:
npm install prop-types yarn add prop-types // or this one, depending on if you are using NPM or Yarn
-
Open up Product.js in our existing project and add the import to the top, like so:
import PropType from 'prop-types';
-
Define the shape of the input by adding this code, just before the export statement:
Product.propTypes = { data : PropType.shape({ name: PropType.string.isRequired, }) };
What the above says is, there, should be a
data
property set. The value set is an object/shape and should have aname
property. -
The full file should now look like so:
import React from 'react'; import PropType from 'prop-types'; const Product = (props) => <div>{props.data.name}</div> Product.propTypes = { data : PropType.shape({ name: PropType.string.isRequired, }) }; export default Product;
-
To show your configuration works as it should, open up index.js and locate the following section:
const products = [ { name: 'Game console' }, { name: 'Game' } ]
and change it to the following:
const products = [ { name: 'Game console' }, { title: 'Game' } ]
note how the second item has the property
title
. This should makeprop-types
fail. Remember, your instruction said that any data passed to aProduct
element should have aname
property. By you passing this data to aCart
component (that rendersProduct
components ), an error should show. -
Run the command
npm start
:npm start
-
Navigate to http://localhost:8080 and open up Developer tools. In the console section you should now have a warning saying something like:
react.development.js:220 Warning: Failed prop type: The prop `data.name` is marked as required in `Product`, but its value is `undefined`.
Great, your instruction is working. To fix this issue just go to
index.js
and rename thattitle
property back toname
.
It is considered best practice to use this lib. It's further considered a best practice to mark up every single input with a specific type. Also it's considered a better practice to move in the propTypes
as member of the class, like so:
class Jedi extends React.Component {
static propTypes = {
jedi : PropType.shape({
name: PropType.string.isRequired,
})
};
render() {
return (
<div>Name: {this.props.jedi.name}</div>
);
}
}
You were introduced to props. They are the way we are able to pass data into a component. You have learned the following:
- You declare them as an attribute on your React element when you want to pass in something
<Elem attr={data}>
- You can pass in object or a list, both works.
- You should use the library
prop-types
to ensure our component get the data they expect so we can capture errors early.