Make a Django app as usual
When working with React, Django mainly serves as an API. Django REST framework is a must.
Make a React app as usual
The react app can be created with create-react-app, it doesn't really matter. Whenever you need to make an API request to get data to render, fetch it from the API you just made with Django. Of course you can use dummy data if you start off with React instead of Django.
Integration
There should be at least 3 folders in your Django app:
-
project/projectfolder, meaning the one withsettings.py -
project/apifolder, the one with the apimodels.py,serializers.pyetc. -
project/frontendfolder, it's created bymanage.py startapp frontendcommand and in this folder, more folders should be created:
-
srcfolder: contains anindex.jsfile and all other react components insrc/componentsfolder -
static/frontendfolder: wheremain.jsfile lives after you runnpm run buildornpm run dev(depends on the script you write --> keep reading) -
templates/frontendfolder: where you store your django templateindex.html, remember you can use django template language/syntax in these html files
Reminders - Make sure:
- you added
frontendapp in yoursettings.py - added
{% load static %}and<script src="{% static 'frontend/main.js' %}></script>inindex.html - added
indexfunction in yourviews.pyfile - added according url patters in your
urls.pyfile - included url patterns in
frontend/urls.pyintoproject/urls.pyfile
Webpack configuration:
Assuming you've had Node.js installed
1. package.json
$ npm init -y
To create a package.json file with all your javascript dependencies, -y means to install the defaults and not answering any questions
Now the package.json file looks like this:
{
"name": "frontend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
2. install webpack and webpack-cli
$ npm i -D webpack webpack-cli
-D means to install as Development dependencies
Now a new key added to package.json file:
{
// ...
"devDependencies": {
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11"
}
}
3. install babel and react preset
$ npm i -D @babel/core babel-loader @babel/preset-env @babel/preset-react babel-plugin-transform-class-properties
-
@babel/core: the babel core package -
babel-loader: helps to transpile the code -
@babel/preset-env: compile down ES6 to be compatible with other versions -
@babel/preset-react: react preset -
babel-plugin-transform-class-properties: handles static class properties for ES2015 and ES2016
Now the package.json file looks like this:
{
// ...added in step 1
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"@babel/preset-react": "^7.9.4",
"babel-loader": "^8.1.0",
"babel-plugin-transform-class-properties": "^6.24.1"
// ...added in step 2
}
}
4. install react and react-dom
$ npm i react react-dom prop-types
- prop-types: > Runtime type checking for React props and similar objects.
Now the package.json file looks like this:
{
// ...added in stop 1,2,3
"dependencies": {
"prop-types": "^15.7.2",
"react": "^16.13.1",
"react-dom": "^16.13.1"
}
}
In my project, I also installed other dependencies: $ npm i react-router-dom react-markdown react-syntax-highlighter react-spring styled-components
And you might need to install more loaders for different file types:
-
$ npm i -D style-loader css-loaderfor css files -
$ npm i -D file-loader url-loaderfor image files
5. create file: .babelrc
In order to use the previously installed presets and plugin, we need to create a .babelrc file.
~/project/frontend/.babelrc
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["transform-class-properties"]
}
6. create file: webpack.config.js
Whenever you use webpack you'll have this config file. All we want to do here is to load babel-loader:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
],
},
};
What the object does:
-
test: a regular expression to look through all of the js files -
exclude: excludenode_modulesfolder -
use: thebabel-loaderto transpile our code
The above is the simplest webpack config file. In real cases, there must be more loaders installed, you can refer to the offical document for more information. At the end, my webpack.config.js becomes:
module.exports = {
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
},
},
{
test: /\.(png|jpe?g|gif|svg)$/i,
use: [
{
loader: "url-loader",
options: {
limit: 8192,
},
},
],
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
};
7. write scripts in package.json
To compile our React app which lives in the frontend app, some scripts have to be defined:
~/project/frontend/package.json
{
// ...
"scripts": {
"dev": "webpack --mode development --watch ./src/index.js --output ./static/frontend/main.js",
"build": "webpack --mode production ./src/index.js --output ./static/frontend/main.js"
}
// ...
}
The scripts defined above would enable us the following commands:
-
$ npm run dev: runwebpack, use--mode development,--watchevery updates in./src/index.jsfile, and compile it to./static/frontend/main.jsfile -
$ npm run build: does a few extra thing for production
8. $ npm run dev
After this script is run, main.js file will be ready to use.
Notes on routing
- In the MAIN
urls.pyfile, include the frontend urls at then end - Use
re_path()method in frontendurls.pyfile to define the url pattern - Use extra 'negative lookahead' to exclude api calls in order to avoid url clash between different django apps (in this case the
frontendapp and myapiapp which serves the api calls):re_path(r'^(?!api)(?:.*)/?$', views.index),
A remember of npm commands
npm uninstall <name>removes the module fromnode_modulesbut does not updatepackage.jsonnpm uninstall <name> --savealso removes it fromdependenciesinpackage.jsonnpm uninstall <name> --save-devalso removes it fromdevDependenciesinpackage.jsonnpm uninstall -g <name> --savealso removes it globally
Top comments (0)