Full-Stack With Django and React — React

Barış Dede
The Startup
Published in
9 min readAug 5, 2020

This article is a continuation of Django and React Full Stack — Django. If you have not read that part or your backend environment is not ready, you can find the article I developed using Django — I shared my notes while developing — here.

I know it’s a very comprehensive title so I’ll keep it as simple as possible.

In this article, we will make a book application from installation to the final product using Django and React. I hope to make a nice and simple introduction-development-product series for a CRUD (Create, Read, Update, Delete) application. I want to share the notes I took and the steps I followed while making an app without getting overwhelmed by a lot of information from both sides (back end and front end).

I will try not to dwell on the questions such as what and why, but to explain it purposefully. For every command I use, I will cite since there may be people who do not know, in this way you can quickly get an idea from their documentation pages and return to the article.

Django is a Python-based free and open-source web library based on the model-template-view architecture.

React is a JavaScript library that allows you to create user interfaces for your web projects on a component basis.

Getting started #1

We established our backend structure with Django, we used our data with HTML. Now it’s time to heat things up a bit. If you still haven’t read that article, you can read it here.
We can start by installing our React application in our project.

Installation

Inside of our project, run npx create-react-app frontend on the command line. The reason I create a project called Frontend is that I don’t want the files to interfere and appear more understandable. I want the node files and Django files in separate folders so that they are easy to access and edit.

After installation is done, run cd frontend & npm start commands. While running the project browser will be opened automatically and you’ll see your first react app. If it runs on another port you can see which port react using is on the terminal screen.

How much should I know?

If you use React the first time or you’ve never written JavaScript you may have some struggle. If we consider it as JavaScript, not just React: it can be a bit annoying to adapt to an asynchronous language. JavaScript is not a completely top-down language. Do not be surprised if the code you write at the bottom works before you write at the top. It is beautifully described as titles at https://javascript.info/. At least, getting enough information to understand what you read later in the article will make your job easier in the continuation of the article.

Functional Components

To create our interface we’ll use functional components. The reason we prefer functional components is that convenience about readability, renewability, and testing.

I don’t want to dig the difference between class and functional components. Focusing on the pros and cons of them will probably deflect us from our main goal of this article. If you want to focus on these, you may follow the link below.

Function and class components: https://tr.reactjs.org/docs/components-and-props.html

The idea of developing based on functional components will be saved us from excess codes and disorganization.

The above code is the first functional component that comes with the installation of react. It returns a DOM element which includes header, image and a text. It looks clean and basic, right? Let’s start with writing code that lists our books.

With basic HTML knowledge we prepared a template for our books list. The only difference between HTML and JSX is that we used className instead of class — for now.

Hooks — useEffect ve useState

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.(https://reactjs.org/docs/hooks-intro.html#no-breaking-changes)

In React lifecycle there’s some methods such as componentDidMount , componentDidUpdate andcomponentWillUnmount . With hooks we use useEffectfor all of them .

Let’s import useState and useEffect and define our first state inside of function.

import {useState, useEffect } from 'React'function App(){...
const [books, setBooks] = useState([])
...
}

I defined a state named books and initialized it with an empty array. This process was as follows in the class components:

class Test extends React.Component{
constructor(props){
super(props)
this.state = {
books : []
}
}
}

Now we see first benefit of functional components. Let’s try to fill our state and use it with useEffect.

useEffect (() => {
setBooks([
{
"name":"Otostopçunun Galaksi Rehberi",
"author": "Douglas Adams",
"description": "Lorem ipsum"
},
{
"name":"Hikayeler",
"author": "Edgar Allan Poe",
"description": "Lorem ipsum sit door amet"
}
])
},[])

We placed two objects in our books state. Now, let me print them with JSX using Array.prototype.map

books.map((book,index) => {
return (
<div className="book-item">
<h2>{book.name}</h2>
<p>{book.author}</p>
<p>{book.description}</p>
</div>
)}
)}

When we run our code, we can now see the data. However, we will get this data from the API we prepared with django. On the Django side, we received our data with XMLHttpRequst operation with pure javascript. We can run the same code again, but we will go one step further and this time we will use the Fetch API, which allows us to retrieve data from a different address.

Fetch API

We will get our data via the REST API that I prepared with Django. If you have not read this series from the beginning and are using a different backend infrastructure, this process will be the same on front-end side.

Let’s send a request to get our data from API and store them.

useEffect (() => {
async function fetchBooks() {
const res = await fetch("http://127.0.0.1:8000/books/");
res.json()
.then(res => setBooks(res.response))
.catch(err => setErrors(err));
}
fetchBooks();
},[])

You may find more information about async functions from this link. To explain this with an example:

getBooks = () => {
console.log('first book');
setTimeout(() => {
console.log('second book');
},3000);
console.log('third book');}
getBooks ();

JavaScript has a sync and single-thread structure. After printing first bookin the above code, it will print third bookand then wait for 3 seconds and display the second bookoutput. The reason we use asyn function is that we want it to wait for that 3 seconds.

Now returning to the react side (I assume Django and React are working) when we open the browser, we will see an error on the console like this:

Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell browsers to give a web application running at one origin, access to selected resources from a different origin.

In order to our API resource to grant this access, we need to configure Django.

Runningpipenv install django-cors-headers code on back-end side we install django-cors-headers app. You may see more details of its installation on the documentation page.

After installation is done configure settings.py file as follows:

Add corsheadersinto INSTALLED_APPS and 'cors.headers.middelware.Corsmiddleware into MIDDLEWARE .

Now we should determine which addresses can be accessed. We can do this in two ways: allowing all addresses or determine particular addresses.

CORS_ORIGIN_WHITELIST = [
"https://example.com",
"https://sub.example.com",
"http://localhost:8080",
"http://127.0.0.1:9000"
]

You may also use a regex pattern. After saving the file, now we can see the data on the browser.

Since we run it in a way, we can do a little more simplification. Let’s not forget that we work component-based. We printed our books on the screen in a direct loop. Let’s take this data as a separate component.

We create a new function called Book and set its return value as the elements we list in our books.

We received the prop named book from the incoming props and we can now print it on the screen. When we add <Book book={item} key={index} />code between our map code in the app, will see the same list again. (I changed the name of the book variable to item to avoid confusion)

For the repetitive values, React asked us to send a selector, so we sent our index value into the key.

Now, let’s move book creation page to React side. We create a new component and place our form elements in it.

Axios

We created our form in a basic way. We will use Axios to send our data to API within POST method. In doing so, we will benefit from React Hooks. We will keep our input values in the state, and when we press the save button, we will catch the submission and perform the operations we want with axios.

CSRF Token

When we send our form we’ll see it will not be saved and return 400 status code(Bad request). The first reason of it is that back-end side await a csrf token from us. In the documentation page, you can see how you can send csrf token. We will use same getCookie function which exists in documentation page. Default cookie name is csrftoken , if you desire you may change it from settings.py page.

Now, we can see the csrftoken information on the network tab of the browser. But, what!? It still returns 400 status code. When we check our serialize code on back-end side we realize that the data we are trying to save is empty. BooksSerializer(data=request.POST or None)

The output of print(request.POST) is <QueryDict: []> . Now the value we need is request.data instead of requst.POST . After changing the data we try to serialize with request.data, we can save it.

Learn more about CSRF Token parameters you may visit this page.

React Routing

Last but not least, we want it to be separated pages with special URLs. We can do these things in a single page but I want it to touch router structure too.

Paste it onto the command line: npm install react-router-dom

I’ve done all components in a single page, you can import seperated components onto different pages and folders using import { ComponentName } from ‘path/file and use them as <ComponentName />

App component lists our books and there is a form also. Let’s separate them and set a router. Keep App component which lists our books. Remove export default App code from bottom of the file to change our default function as router.

Like me, do not forget to import the libraries you use.

import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";

Now, to make Landing component index page, change the default component as Landing in index.js file.

When we refresh the page, we will see the menu links we created in the form of a list at the top of the page. Since we are in the main directory, the <App /> component will be called and our books will be listed.

Let’s write the code to show singular book with an id in a page. It’s almost same with our full list code. The only difference is that if it doesn’t exist in our database it will return an error message. We already configured our API to return a 404 page if there’s no data. We’ll control it with a status message such as ok/error. And let’s write our code as follows:

Now, when we enter localhost:3000/books/1 address, if there’s a data with 1 id in the database, it will print it. If an error occurs or our status code is not 200, it will print the message “Something went wrong” on the screen.

In the code we list our books, add a hyperlink to our titles to be able to go into the details page.

Change book listing code as follows:

Now we can click the titles and go into their detail pages.

After everything is completed, we can build our optimized react application via npm run build and see them in a folder named build.

So far, we didn’t do anything about styling. I’ll add CSS codes later to the repository but our main goal is to try to understand the main structure. We could deal with CSS later on. You can see the source codes I use in this article on Github, and contribute if you wish.

You can contact me if you have any questions or about anything you need via my Twitter account.

Happy codding! :)

Github, Twitter, Instagram : @baris5d

--

--