Intro (Skit)
First and foremost I would like to apologize for making you
Interlude:
Wake up and smell the dour time for an early session seeks to serialize and give examples Shebang as much as I would love to django I need to lay back Head stash the size of the pillow I rest my head on restful and node, just to appreciate the script front to back back 2 back too back frontin react crud crud My depositions never surface and that's the 20/20 ishy const args kwargs we don't cors these lines we inhale these lines that's a callback function for your queryset you dig.
Let's get the basics out of the way. React is not another MVC framework or any other kind of framework. It's just a library for rendering your views. If you're coming from the MVC world, you need to realize that React is just the 'V', part of the equation, and you need to look elsewhere when it comes to defining your' "M" and "C", that's where that RESTful API that we created previously with Django comes in very hand otherwise, you're going to end up with some really yucky React code. React got that name for a reason. It’s a component-based JavaScript library that renders smartly and can seriously simplify your work.
Now that the "M" and "C" are out of the equation this article will help you understand a few concepts you need to know in order to integrate a RESTful API in a React application.
We will be building a simple Artist's list application to display the Artist name, bio, and list of albums from each artist. We will make use of the endpoint provided by our API "http://192.168.0.250:7000/artists/", it contains a JSON dump of data needed for our artist list application. You can get the code of a this project on github (fished version)
Too many "beginner React" material starts with JSX and a bunch of tools. React itself is remarkably simple (and the docs are amazingly good). Sadly, everything around it can get complicated quickly and it can be hard to know where the lines are between React and the tools and libraries you use it with. Because of this, Your can think of this article as your Beginner's Guide to React I'll absolutely try to avoid using a lot of tools and libraries such as redux, axios and so on. That being said the following are the prerequisites that might be hand in order for you to follow along:
Prerequisites
- Basic understanding of JavaScript
- Basic understanding of CSS
- Basic understanding of APIs
- Must have nodejs installed on your local machine
- RESTful API to consume
Getting Started
I'll strat by navigating to where I want to host my appcd project
mkdir react
cd reacte
I'll use Create React App which is an officially supported way to create single-page React applications. This will generate some scaffolds.
npx create-react-app frontend
cd frontend
Enumerate your directory and files structure
ls
node_modules package.json public README.md src yarn.lock
Remove everything inside
src
directory make sure it's empty. And inside public
directory remove everything except the index.html
file. So in the end you have empty src
directory and one file which is index.html
inside the public
directory. Project setup
Create a new file insidesrc
director and call it index.js
touch src/index.js
Every application you will develop in React will be made up of pieces called
components
. Components in React basically returns a piece of JSX
code which tells what should be rendered on the screen...., more on that later but for now you should know that on our appliction we are going to have three parent components namely home, artist, and 404 (page not found). Inside your src
directory you should create the following directory components
and then populate it with the following files home.js
artist.js
and default.js
like so.mkdir src/components
touch src/components/artist.js
touch src/components/home.js
touch src/components/default.js
Routing
At the core of every React Router application should be a router component. For web projects, react-router-dom provides <BrowserRouter
> and <HashRouter
> routers. Both of these will create a specialized history object for you. Generally speaking, you should use a <BrowserRouter
> if you have a server that responds to requests like we do and a <HashRouter
> if you are using a static file server. React Router DOM is published to npm so you can install it with either npm or yarn. I'll proceed by installing react-router-dom using npm.npm install react-router-dom
Open the
src/index.js
file and import the three components (artist,home,default
)nano src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
// COMPONENTS
import Home from './components/home';
import Artist from './components/artist';
import Default from './components/default';
ReactDOM.render(<App />, document.getElementById('root'));
We are using three components out of React router Dom [
BrowserRouter, Route, Switch
] which will help us to implement the routing.Route Matching
There are two route matching components: <
Route
> and <Switch
>.Route matching is done by comparing a <
Route
>'s path prop to the current location’s pathname. When a <Route
> matches it will render its content and when it does not match, it will render null. A <Route
> with no path will always match.// when location = { pathname: '/home' }
<Route path='/home' component={Home}/> // renders <Home/>
<Route path='/artist' component={Artist}/> // renders null
<Route component={Default}/> // renders <Default/>
Switch
The <
Switch
> is not required for grouping <Route
>s, but it can be quite useful. A <Switch
> will iterate over all of its children <Route
> elements and only render the first one that matches the current location. This helps when multiple route’s paths match the same pathname when animating transitions between routes, and in identifying when no routes match the current location (so that you can render a “404” component).That is Switch component helps us to render the components only when path matches otherwise it fallbacks to the not found component.
If you were to manually enter
localhost:3000/artist
you will see Artist component is rendered.And also the, Home component is rendered in the screen this happens because of our home path is ’/’ and artist path is ‘/artist’ slash is same in both paths so that it renders both components to stop this behavior we need to use the exact prop.<Switch>
<Route exact path="/" component={Home}></Route>
<Route path="/artist/:artistid" component={Artist}></Route>
{/* when none of the above match, <Default> will be rendered */}
<Route component={Default} />
</Switch>
Url Parameters
Url parameters help us to render the same component based on its dynamic URL like in our Artist component in our particular scenario we will have different artists with id 1,2,3. Hence
<Route path="/artist/:artistid" component={Artist}></Route>
Implement routing.
You have three prop choices for how you render a component for a given <Route>: component, render, and children. You can check out the
In the Route component, we need to pass the two props
path: it means we need to specify the path.
component: which component user needs to see when they will navigate to that path. Now that the basics of route are understood lets put some code on our
src/index.js
nano src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
// COMPONENTS
import Home from './components/home';
import Artist from './components/artist';
import Default from './pages/Default';
const App = () =>{
return (
<BrowserRouter>
<div>
<Switch>
<Route exact path="/" component={Home}></Route>
<Route path="/artist/:artistid" component={Artist}></Route>
<Route component={Default} />
</Switch>
</div>
</BrowserRouter>
)
}
ReactDOM.render(<App />, document.getElementById('root'));
Components
At this stage, if you attempt to start the react app and visithttp://ip:3000/
you will see some errors in your browserIn order to avoid that let's edit the
home.js
file inside the components directory. You should be very aware by now that everything in React is a component, and these usually take the form of JavaScript classes. You create a component by extending upon the React-Component class.nano src/components/home.js
import React,{ Component } from 'react';
class Home extends Component {
render(){
return(
<div>Home</div>
)
}
}
export default Home;
You then define the methods for the component. We only have one method, and it’s called
render
(). Inside render
() you’ll return a description of what you want React to display on the page. In the case above, we simply want it to display the text Home. To get our tiny application to render on the screen, we also have to use ReactDOM.render
(): So this is where we connect our Home component with the entry point for the app (<div id="root"></div>)
. So we’re simply saying: Hey React! Please render the Home component inside the DOM node with an id of root! Now if we visit our site
http://ip:3000/
we should see thisReact Arrow Function Component
Go to the
components
directory and create a new components call it banner.js
by the way I've used, className to reference classes defined in an external CSS stylesheet. Style is most often used in React applications to add dynamically-computed styles at render time.
nano src/components/banner.js
import React from 'react';
const Banner = () =>{
return(
<div> className="banner">
<div> className="main_cover">
<div> className="logo">MUSIC-DB</div>
</div>
<span></span>
</div>
)
}
export default Banner;
React Arrow Function Components use a function block body, the second component can be made more lightweight with a concise body for the function, because it only returns the output of the component without doing something else in between.
The definition of the component happens with just a JavaScript Function which has to return JSX -- React's syntax for defining a mix of HTML and JavaScript whereas the JavaScript is used with curly braces within the HTML. In our case, we return some JSX we don't send any props we just want data, we will render an image cover, logo and underneath the image, we will have a blue line(the reason I have that span there so that I can apply some style underneath the image to get a blue line with CSS),
Now navigate to
Now navigate to
public
directory and create a css
directory inside css
directory you will create styles.css
file like somkdir public/css
nano public/css/styles.css
body{
margin:0;
font-family:"Roboto"!important;
background: #eaeaea;
}
a {
text-decoration: none;
color:inherit;
}
/* =======================================
BANNER
==========================================*/
.banner .main_cover {
background:url('../images/cover.png');
height:400px;
background-size: cover;
background-position: center center;
position: relative;
height: 465px;
}
.banner .logo {
font-family: 'Monoton', cursive;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 100%;
height: 62px;
color: #FFF;
font-size: 43px;
text-align: center;
}
.banner span {
display: block;
height: 20px;
background: #2196F3;
}
you will also need to create
images
directory inside public
directory mkdir public/images
public.index.html
file and add the following on the head sectionnano public/index.html
<link href="https://fonts.googleapis.com/css?family=Monoton|Roboto:300,400,700" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="/css/styles.css">
Open up the
src/components/home.js
and alter it to include the banner
component as its childnano src/components/home.js
import React,{ Component } from 'react';
import Banner from './banner'
class Home extends Component {
render(){
return(
<div>
<Banner></Banner>
</div>
)
}
}
export default Home;
now go check out the result at
http://ip:3000/
Feeding dynamic data from the API
Most modern web applications make use of the REST Protocol to communicate with each other. To achieve this, data is sent as JSON (JavaScript Object Notation) to the API. In turn, the API returns a JSON payload which can be static or dynamic data. Our application will parse and display the data in a presentable manner, making it appealing to the user. A state is simply an object that holds data pending to be rendered. This
is where we will store the output from the API call. We will build a
list of the artists by creating a functional artists list component
which is going to receive some data, we will fetch the list of artists
from the API in the home component then we are going to parse the list of
artists to that child component which in this case it will be artists
list component. Whenever we fetch the information we want to set it to
the state so we can parse it as props. Notice: I've used the keyword
super so that I can parse props.Let's create a state to store the output from our API request. Open up the
src/components/home.js
file and add the
following.nano src/components/home.js
import React,{ Component } from 'react';
import Banner from './banner'
// REQUESTS URL
const URL_ARTIST = 'http://192.168.0.250:7000/artists'
class Home extends Component {
constructor(props){
super(props)
this.state = {
artists:''
}
}
render(){
return(
<div>
<Banner></Banner>
</div>
)
}
}
export default Home;
Create artists list component like so, I'll log the info to the console at the moment just to make sure if I'm getting the data.
nano src/components/artistsList.js
import React from 'react';
const ArtistsList = (props) =>{
console.log(props)
return(
<div>List</div>
)
}
export default ArtistsList;
Calling the API
To fetch our artists list, we will use a
componentDidMount
() method in our Home.js
file. This method is executed immediately our component is mounted and we will also make our API request in that method. Let's spice up a bit our Home.js
file shall we!nano src/components/home.js
import React,{ Component } from 'react';
import ArtistsList from './artistsList';
add thisimport Banner from './banner'
// REQUESTS URL
const URL_ARTIST = 'http://192.168.0.250:7000/artists'
class Home extends Component {
constructor(props){
super(props)
this.state = {
artists:''
}
}
// add this
componentDidMount() {
fetch(URL_ARTIST, {
method: 'GET'
})
.then(response => response.json())
.then(json => {
console.log(json)
})
}
render(){
return(
<div>
<Banner></Banner>
<ArtistsList></ArtistsList>
add this</div>
)
}
}
export default Home;
fetch('URL_ARTIST')
will make a GET request to the endpoint http://192.168.0.250:7000/artists
, .then(res => res.json())
parses the output to JSON
, .then((json) =>
(console.log)
logs any data we get to the console. Go to your browser http://ip:3000/
and inspect the element check out the console tab if using firefox or chrome, you should be getting the JSON data from API like so.In order for us to be able to display the data we need to sets the value of our state (artists state) to the output from the API call, will need to update the child component
ArtistsList
and pass the props which is going to be the state that we have inside artists, will then need to update the artistsList
component so that it grabs the props that have been parse by the parent home.js
so to make it clear let's go and update the code.nano src/components/home.js
import React,{ Component } from 'react';
import Banner from './banner'
import ArtistsList from './artistsList';
// REQUESTS URL
const URL_ARTIST = 'http://192.168.0.250:7000/artists'
class Home extends Component {
constructor(props){
super(props)
this.state = {
artists:''
}
}
componentDidMount() {
fetch(URL_ARTIST, {
method: 'GET'
})
.then(response => response.json())
.then(json => {
this.setState({artists:json})
})
}
render(){
return(
<div>
<Banner></Banner>
<ArtistsList allArtists={this.state.artists}></ArtistsList>
</div>
)
}
}
export default Home;
We make a request to the API and then we get the list of
{artists:json}
. once we get the list we are passing it as props (allArtists)
to the child component (ArtistsList)
with all the list of the artist {this.state.artists}
, in order to render a list of artists we need to grab that props in our artistsList component by creating a function that will render the props (allArtists), before we do that let's first examine if we are getting that particular props (allArtists)
on artistsList component we need to modify a bit the code of artistsList component and consol log to make sure we do get (allArtists)
props.nano src/components/artistsList.js
import React from 'react';
const ArtistsList = (props) =>{
const list = (props) => {
console.log (props)
}
return(
<div className="artists_list">
<h4>Browse the artists</h4>
{list(props)}
</div>
)
}
export default ArtistsList;
Now Go to your browser and inspect
http://ip:3000/
Yes indeed we can see that we do get the props
(allArtists)
yet again we will edit the file and add some ES6 destructuring the destructuring assignment syntax
was introduced to JavaScript in ES6, it is a simple way of extracting
data stored in objects and arrays into variables. This article is not
intended to be an in depth look at the destructuring syntax, if that’s
what you’re after a quick Google search should give you what you need, instead I'll show how we can use it inside our React components. and we should also make sure that when we get that list and click on
item we navigate to a new route After adding navigation you will see the
routes are rendered on the screen. if you click on the artist you will
see URL is changing and Artist component is rendered. React Router provides a <Link>
component to create links in your application. Wherever you render a <Link>
, an anchor (<a>)
will be rendered in your application’s HTML.nano src/components/artistsList.js
import React from 'react';
import { Link } from 'react-router-dom';
Adding navigation using Link componentconst ArtistsList = (props) =>{
const list = ({allArtists}) => {
ES6 destructuring, we already know we have the list of all artistsif(allArtists){
we check if we have datareturn allArtists.map((item)=>{
we return what ever we get on the map of all artist after each iteration we pass itemreturn (
<Link key={item.id} to={`/artist/${item.id}`} className="artist_item">
link has to have a key item, we get the id from our API which is unique. So we can use it as a key, by the way react always ask you to provide id<div>
<img alt="" src={item.cover}
each artist has an imagestyle={{ maxHeight: "25rem" }}
a bit of style to the imageclassName="artist_item"
/>
<div>
{item.name}
we need to display the name of each artist </div>
</div>
</Link>
)
})
}
}
return(
<div className="artists_list">
<h4>Browse the artists</h4>
{list(props)}
that's how we display the list of artist by trigger a function then pass a props as argument</div>
)
}
export default ArtistsList;
Need to update the css file once again open up the
styles.css
file in your public
directory append this piece of codenano public/css/styles.css
/* =======================================
ARTISTS LIST
==========================================*/
.artists_list {
margin: 45px;
text-align: center;
font-size:2em;
border-radius:2px;
border:1px solid #bbb;
transition: all 0.3s linear;
}
.artists_list .artist_item:hover {
-webkit-box-shadow:rgba(0,0,0,0.8) 0px 5px 15px, inset rgba(0,0,0,0.15) 0px -10px 20px;
-moz-box-shadow:rgba(0,0,0,0.8) 0px 5px 15px, inset rgba(0,0,0,0.15) 0px -10px 20px;
-o-box-shadow:rgba(0,0,0,0.8) 0px 5px 15px, inset rgba(0,0,0,0.15) 0px -10px 20px;
box-shadow:rgba(0,0,0,0.8) 0px 5px 15px, inset rgba(0,0,0,0.15) 0px -10px 20px;
}
.artists_list:after {
clear: both;
display: table;
content:''
}
.artists_list .artist_item {
float: left;
padding: 10px;
background: #2196F3;
color: #fff;
bottom: 0;
margin-bottom: 1em;
}
.artists_list h4 {
font-family: 'Monoton', cursive;
text-align: center;
font-size: 30px;
font-weight: 100;
margin: 20px 0px;
color: #8887B1BF;
}
Go to your browser
http://ip:3000/
header
and albumList
, the header
component will be functional component responsible to display a logo and when you click it you will navigate to the home page, albumList
component will be responsible to display the list of the album for each artist while the parent component artist
will be responsible to display the image of the artist, bio and artist name, and we will use state since we will be parsing props.nano src/components/header.js
import React from 'react';
import { Link } from 'react-router-dom';
we bring in the link component so that we can have navigation functionality.const Header = () =>{
return(
<header>
<Link to="/">Music db</Link>
a clickable logo, once clicked you will navigate to the home page </header>
)
}
export default Header;
nano src/components/artist.js
import React,{ Component } from 'react';
import Header from './header';
child componentsimport AlbumList from './albumList';
child componentsconst REQ_URL = `http://192.168.0.250:7000/artists
`class Artist extends Component {
constructor(props){
super(props)
this.state = {
artist:''
}
}
componentDidMount() {
fetch(`${REQ_URL}/${this.props.match.params.artistid}`, {
method: 'GET'
})
.then(response => response.json())
.then(json => {
this.setState({artist:json})
})
}
render(){
return(
<div>
<Header></Header>
<div className="artist_bio">
<div className="albums_list">
<img src={this.state.artist.cover}alt="artist"/>
</div>
<div className="bio">
the class Name will be hand when we work with css<h3>{this.state.artist.name}</h3>
<div className="bio_text">
{this.state.artist.bio}
the bio is inside the state</div>
</div>
<AlbumList albumList={this.state.artist.albums}/>
the album is inside the state</div>
</div>
)
}
}
export default Artist;
create a stateless component which is going to receive props
nano src/components/albumList.js
import React from 'react';
const AlbumList = (props) => {
const showList = ({albumList}) =>{
destructuring this props is originating from the parent componentif(albumList){
check to see if we have datareturn albumList.map((item, index)=>{
we iteration over image, we use index so that we can go from 1, 2, etc through all the element you have on the listreturn (
<img key={index} alt="" src={item.cover}/>
the key is required and I'll point it to index, and the image is item.cover item is what we have already defined and the cover is the source of the filename)
})
}
}
return(
<div className="albums_list">
{showList(props)}
</div>
)
}
export default AlbumList;
Now let's work on 404 page not found this is is our default parent component the last one one for this
article I'll no't go into details as what exactly is happening with the code because we already took care of that if you have come this far this should be a piece of cake I'll just paste the code and I hope you will know what's going on under the hood
nano src/components/defaultheader.js
import React from "react";
export default function defaultheader({ children, title, styleClass }) {
return (
<defaultheader>
<div className={`row align-items-center ${styleClass}`}>
<div className="col text-center">
<h1 className="text-defapri text-uppercase">
{title}
</h1>
{children}
</div>
</div>
</defaultheader>
);
}
defaultheader.defaultProps = {
title: "default title",
styleClass: "header-hero"
};
nano src/components/default.js
import React, { Component } from 'react';
import Defaultheader from './defaultheader';
import Banner from './banner';
import { Link } from 'react-router-dom';
export default class Default extends Component {
render() {
return (
<div>
<Banner></Banner>
<Defaultheader title="404" styleClass="default-hero">
<h2 className="text-defapri text-uppercase">
The page you're looking for doesn't exist
</h2>
<Link to="/" className="text-defapri text-uppercase">
return home
</Link>
</Defaultheader>
</div>
);
}
}
Need to update your css file there some class that I have defined but you will notice that I haven't apply any styling to those classes. Well you can take it up a notch and work out the style in whatever manner that suits you. Ok open up your
styles.css
file and add the following:nano public/css/styles.css
/* =======================================
HEADER
==========================================*/
header {
font-family: 'Monoton', cursive;
text-align: center;
font-size: 33px;
border-bottom: 1px solid #2196F3;
color: #949494;
}
/* =======================================
ARTISTS BIO
==========================================*/
.artist_bio{
box-sizing: border-box;
padding: 10px 30px;
}
.artist_bio .avatar span {
width: 130px;
height: 130px;
display: block;
margin: 0 auto;
background-size: contain !important;
}
.artist_bio h3 {
font-weight: 100;
text-align: center;
font-size: 30px;
margin: 10px 0px
}
.artist_bio .bio_text {
font-size: 20px;
width: 70%;
}
.albums_list {
margin: 20px;
}
.albums_list:after {
clear: both;
display: table;
content:''
}
.albums_list > img {
float: left;
width:50%;
}
/* =======================================
Default 404
==========================================*/
.text-defapri {
text-align: center;
font-family: cursive;
text-align: center;
font-size: 33px;
font-weight: bold;
color: #724545;
}
.text-uppercase {
text-transform: uppercase;
background: #ffb7b7;
}
.default-hero {
min-height: calc(125vh - 50px);
background: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)),
url("../images/defaultBcg.png") center/cover no-repeat;
}
Go to your browser
http://ip:3000/artist/1
Go to your browser http://ip:3000/gft
Congrats!! if you made it this far it was't too bad, now you can lit it up a notch dive into redux, axios and so long let React hook... till then the crack is on you 😉 happy hacking!!
outro:
Never work away from a dollar that make sense.