Create a basic ReactJS app with no config
Apr 11, 2017
There are many ways that a ReactJs app can be created. The aim of this guide is to get up and running with a basic react app as quickly as possible.
That means no other fancy libraries such as Redux, Router, Relay or anything else beginning with R (seems like there is a theme going on). There’s also going to be no Flux or jQuery or any other async included and certainly no configuration needed via WebPack, Babel or Gulp.
How do we get started so easily… Thankfully there is Facebook’s Create React App. These first step, taken from the CRA will get a new project up and running with no config. It’s from there that we can start to play with React.
First we need to install the tool (You’ll need Node/npm installed beforehand) then we move into the directory and start the app. Mine is called react-01 but you can call it what you want! Open up a terminal window:
1npm install -g create-react-app create-react-app react-01 cd react-01/ npm start
And now you’ll see a basic page with a spinning React logo and some starter instructions “To get started, edit src/App.js and save to reload.”, so let’s do that.
Open up src/App.js
and let’s have a look at making our own components.
1import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; class App extends Component { render() { return ( <div className="App"> <div className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h2>Welcome to React</h2> </div> <p className="App-intro"> To get started, edit <code>src/App.js</code> and save to reload. </p> </div> ); } } export default App;
By default it comes with a bit of extra code that we can get rid of. This may be useful later once you start adding styles and images, but for now let’s start from fresh.
Replace the whole file contents with:
1import React, { Component } from 'react'; class App extends Component { render() { return ( <div> <h1>Hello React!</h1> </div> ); } } export default App;
Save and Voila! You have done your first bit of React. It’s written in JSX too, so you can tick that box also! Let’s not stop there though, we’ve only scratched the surface. We need components. Components can be used just like HTML tags, we just need to define them first before we use them.
Let’s make one now. Add a List component after the import React and before the App component:
1import React, { Component } from 'react'; class List extends Component { } class App extends Component { render() { return ( <div> <h1>Hello React!</h1> <List /> </div> ); } } export default App;
When you save and the page reloads… Nothing… that’s because a component must have a render function to display it’s HTML. The render function can optionally have some logic in it to show and hide content depending on variables but in it’s simplest form it just needs to return some HTML. Please note that from here on in, I’ll mostly be sharing snippets of code and not the whole files each time. Hopefully you can follow along!
1class List extends Component { render() { return ( <h2>List title</h2> ) } }
Now, a list is not very good if it doesn’t have any contents so lets start by adding a <ul>
to contain the elements
1class List extends Component { render() { return ( <h2>List title</h2> <ul> </ul> ) } }
OOPS! Now we have an error. This is because a render function should only ever return one root element. A component can be as complicated as you want inside, but due to the way the DOM is built by the JavaScript it can only ever handle one element at the outer most level of a component. Let’s fix that by wrapping both components in a single <div>
.
1class List extends Component { render() { return ( <div> <h2>List title</h2> <ul> </ul> </div> ) } }
Now let’s make a new component for the ListItems and then put 3 of them in the List component’s <ul>
1class ListItem extends Component { render() { return ( <li>Item</li> ) } } class List extends Component { render() { return ( <div> <h2>List title</h2> <ul> <ListItem /> <ListItem /> <ListItem /> </ul> </div> ) } }
Now we have a basic list, but it’s a bit useless since it’s all static content. We should really populate it from some data. In the real world the data could come from an API, but to keep things simple let’s just add it as a variable for now. Add a variable just after the first line:
1import React, { Component } from 'react'; let list_data = [ "Cat", "Dog", "Fish", "Parrot", "Rabbit" ] ...
Remember when I said we could use some logic in the render function, well now we can. In the List component we need to add add a variable that returns the array of data mapped to the ListItems. Then we render the variable to the HTML
1class List extends Component { render() { // Create variable with mapped data let list_items = list_data.map(function(item, index) { return ( <ListItem /> ) }) // Return the HTML return ( <div> <h2>List title</h2> <ul> {list_items} </ul> </div> ) } }
When we create the variable from the data array we map each element in the array and pass it to a function. The inner function returns the HTML for that item. We can then use the variable in the returned HTML.
Variables in react templates are wrapped in {}. You can also put logic in the brackets, but that can end up looking messy if you have too much in there. I prefer to keep the logic out of the render return as much as I can.
Anyway you should now notice 5 Items (if you used my data array). You will also notice that that they still just say “Item” which is not really that cool. Let’s fix that!
First let’s pass the item text to the ListItem. Note that the item variable (which is an object from the data_list array) is being passed to the ListItem as a Prop called “text”:
1class List extends Component { render() { // Create variable with mapped data let list_items = list_data.map(function(item, index) { return ( <ListItem text={item} /> ) }) // Return the HTML ...
Now let’s update our ListItem to display it’s newly acquired Prop.
1class ListItem extends Component { render() { return ( <li>{this.props.text}</li> ) } }
All good? Well actually no. One of the things that makes react so great is how it updates the UI so quickly and seamlessly. It does most of this using magic, but it does need our help understanding which elements are new, have changes or have been removed. If you open up the browser console you should see an error stating:
Warning: Each child in an array or iterator should have a unique “key” prop. Check the render method of List
That is because React doesn’t know which elements are which. It’ll still render them to the page, but it won’t do it efficiently and that’s bad.
We must help react by giving each element that is mapped a unique key. If we were getting our data from a database/API we could use the id of the item from there. Since we have an array and our map function returns an index we can use that. We should use a unique property for the key. Don't use an index. It's bad for render performance.
1... // Create variable with mapped data let list_items = list_data.map(function(item) { return ( <ListItem text={item} key={item} /> ) }) ...
It was that easy. Looks like nothing changed. It’s now that you should look at getting the React Developer Tools for your browser… Do that now. I’ll wait…
Now back in the browser you should see a react tab in the developer tools panel. Before you click it inspect one of your items as normal.
Then checkout the React tab. See how the React tab shows your component structure and the keys. Have a click around and compare it to the HTML markup.
So now that we have a set of nested components and some data being displayed it’s time to do some housekeeping. If this was a real app and all the Components were in one file that would be a nightmare, not to mention that if we make components in a modular way then we can use them in multiple apps.
Here’s what you should have so far:
1import React, { Component } from 'react'; let list_data = [ "Cat", "Dog", "Fish", "Parrot", "Rabbit" ]; class ListItem extends Component { render() { return ( <li>{this.props.text}</li> ) } } class List extends Component { render() { // Create variable with mapped data let list_items = list_data.map(function(item, index) { return ( <ListItem text={item} key={index} /> ) }) // Return the HTML return ( <div> <h2>List title</h2> <ul> {list_items} </ul> </div> ) } } class App extends Component { render() { return ( <div> <h1>Hello React!</h1> <List /> </div> ); } } export default App;
Making the app modular
Let’s start to make the app more modular. First though, lets add a second list to see why we should do things in a modular way.
1class App extends Component { render() { return ( <div> <h1>List of lists</h1> <h2>Top animals</h2> <List /> <h2>Other animals</h2> <List /> </div> ); } }
At this point we have 2 lists with the content being the same. We could make another list component, but what if we have a third or fourth list to display (I really like lists). We could instead use Props again and pass the list data to the component. Make a new array of animals named other_animals and while we’re at it let’s rename the first list to top_animals
1let top_animals = [ "Cat", "Dog", "Fish", "Parrot", "Rabbit" ] let other_animals = [ "koala", "Chimp", "Tiger", "Shark", "Humming bird" ]
Then in the App component let’s pass a prop to each List with the data they should display
1class App extends Component { render() { return ( <div> <h1>List of lists</h1> <h2>Top animals</h2> <List data={top_animals} /> <h2>Other animals</h2> <List data={other_animals} /> </div> ); } }
Then finally in the List component we need to update the mapping function to use the new data from the prop instead of the old hardcoded array variable:
1// Create variable with mapped data let list_items = this.props.data.map(function(item) { return ( <ListItem text={item} key={item} /> ) })
And there you have it. Multiple lists. Feel free to add some more data arrays and List components.
Housekeeping and better practices
The next step is to make the components their own files. Create a new file in the src folder components/List.js then cut the List component from the App.js file into it. At the top of that file add the react import so you end up with:
1import React, { Component } from 'react'; class List extends Component { render() { // Create variable with mapped data let list_items = this.props.data.map(function(item, index) { return ( <ListItem text={item} key={index} /> ) }) // Return the HTML return ( <div> <h3>List title</h3> <ul> {list_items} </ul> </div> ) } }
Do the same with the ListItem code so you end up with a file named src/components/ListItem.js
containing:
1import React, { Component } from 'react'; class ListItem extends Component { render() { return ( <li>{this.props.text}</li> ) } }
Then in the App.js file we need to import the List component so it can be used.
1import React, { Component } from 'react'; import List from './components/List'; ...
Do the same in the List.js file so that it can use the ListItem:
1 import React, { Component } from 'react'; import ListItem from './ListItem'; ...
The final thing we need to do is (export)[http://stackoverflow.com/questions/21117160/what-is-export-default-in-javascript] each component from it’s file so that it can be imported by others.
Right at the end of List.js file add the following line:
1export default List;
and at the end of ListItem.js file add:
1export default ListItem;
Now all that remains is a little more tidying. Since our list has a few requirements to make it work we should define some PropTypes to help us with error checking (e.g. A component that expects an array of Strings will complain if it gets an Int). It’s a bit more work but it’s a good practice that will end up saving you some headaches when you have forgotten how the component works in 6 months.
Let’s start with the ListItem since it’s the simplest.
1import React, { Component } from 'react'; import PropTypes from 'prop-types'; class ListItem extends Component { render() { return ( <li>{this.props.text}</li> ) } } ListItem.propTypes = { text: PropTypes.string.isRequired }; export default ListItem;
We have set the text prop type to be a string. That means if we pass anything other than a string to the ListItem for the text properly there will be an error logged in the console. Try updating one of the lists with some other values
1let other_animals = [ "koala", "Chimp", "Tiger", "Shark", "Humming bird", null, false, 1 ]
An error caused by a null value:
warning.js:36 Warning: Failed prop type: The proptext
is marked as required inListItem
, but its value isnull
.
An error caused by the wrong type of value
warning.js:36 Warning: Failed prop type: Invalid proptext
of typeboolean
supplied toListItem
, expectedstring
.
It will still render the list, but when you are debugging something later on it’s good to know if you are passing the right values around. Undo that breaking code by removing the null, false and Int values!
Now let’s update the List component. We also need to add a title to it as a property so it’s properly reusable.
1import React, { Component } from 'react'; import PropTypes from 'prop-types'; import ListItem from './ListItem'; class List extends Component { render() { // Create variable with mapped data let list_items = this.props.data.map(function(item, index) { return ( <ListItem text={item} key={index} /> ) }) // Return the HTML return ( <div> <h3>{this.props.title}</h3> <ul> {list_items} </ul> </div> ) } } List.propTypes = { title: PropTypes.string.isRequired, data: PropTypes.arrayOf(PropTypes.string).isRequired }; export default List;
PropTypes can be nested so we can require an array with string values inside. There are many other PropTypes depending on what you need. Now we need to pass a title prop to the List component so in the App.js file let’s get that done.
1... class App extends Component { render() { return ( <div> <h1>List of lists</h1> <List data={top_animals} title="Top animals" /> <List data={other_animals} title="Other animals"/> </div> ); } } ...
And to test our propTypes let’s break it for a moment by updating the other_animals:
1let other_animals = ‘car’;
Failed prop type: Invalid propdata
of typestring
supplied toList
, expected an array.
And you will also see: Uncaught TypeError: this.props.data.map is not a function
This is because the list .map function is trying to map on something that doesn’t have that function available since strings don’t have .map. From the first warning we can see that we’re supplying the wrong kind of variable and can fix things more easily and quickly.
Undo that broken code by setting other_animals back to the array of strings!
So there you have it, you have scratched the surface of React. You have a basic set of nested components that render their (type validated) data. You can (download the final files from GitHub)[https://github.com/Designer023/ReactJS-tutorial-files-01].
This is my first React tutorial and also first tutorial in a long time, so any feedback is most welcome.