How to create a simple code with React & Node
Backend (Node)
We will start by creating a Backend for our app. Create a new folder called server and create an app.js file inside:
const path = require(‘path’);
const express = require(‘express’);
const bodyParser = require(‘body-parser’);
const session = require(‘express-session’);
const cors = require(‘cors’);
const errorHandler = require(‘errorhandler’);
const mongoose = require(‘mongoose’);
mongoose.promise = global.Promise;
const isProduction = process.env.NODE_ENV === ‘production’;
const app = express();
app.use(cors());
app.use(require(‘morgan’)(‘dev’));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, ‘public’)));
app.use(session({ secret: ‘LightBlog’, cookie: { maxAge: 60000 }, resave: false, saveUninitialized: false
}));
if(!isProduction) {
app.use(errorHandler());
}
mongoose.connect(‘mongodb://localhost/lightblog’);
mongoose.set(‘debug’, true);
// Add models
// Add routes
app.use(require(‘./routes’));
app.use((req, res, next) => {
const err = new Error(‘Not Found’);
err.status = 404;
next(err);
});
if (!isProduction) {
app.use((err, req, res) => {
res.status(err.status || 500);
res.json({
errors: {
message: err.message,
error: err,
},
});
});
}
app.use((err, req, res) => {
res.status(err.status || 500);
res.json({
errors: {
message: err.message,
error: {},
},
});
});
const server = app.listen(8000, () => console.log(‘Server started on http://localhost:8000’));
Make sure to install all the packages needed by running this command in terminal inside server folder (where you app.js is):
npm i -S path express body-parser express-session cors errorhandler mongoose morgan
Finally add Nodemon to automatically re-run our app.js everytime we update something.
npm install –g nodemon
And then run nodemon app.js in terminal to restart our app.
Model creation
We will start by creating our Article model which will have a timestamp, author, body & title. Add a new folder inside server folder called models and create a file called Articles.js inside of it.
const mongoose = require(‘mongoose’);
const { Schema } = mongoose;
const ArticlesSchema = new Schema({
title: String,
body: String,
author: String,
}, { timestamps: true });
ArticlesSchema.methods.toJSON = function() {
return {
_id: this._id,
title: this.title,
body: this.body,
author: this.author,
createdAt: this.createdAt,
updatedAt: this.updatedAt,
};
};
mongoose.model(‘Articles’, ArticlesSchema);
Now lets register the model we created into our server/app.js file:
…
mongoose.connect(‘mongodb://localhost/lightblog’);
mongoose.set(‘debug’, true);
// Add models
require(‘./models/Articles’);
// Add routes
app.use((req, res, next) => {
const err = new Error(‘Not Found’);
err.status = 404;
next(err);
});
…
Routing
We will start by creating a route to POST an article model.
Add the following folder structure to your server folder (server/routes):
server/
..routes/
….index.js
….api/
const express = require(‘express’);
const router = express.Router();
router.use(‘/api’, require(‘./api’));
module.exports = router;
Edit routes/api/index.js:
const router = require(‘express’).Router();
router.use(‘/articles’, require(‘./articles’));
module.exports = router;
Edit routes/api/articles.js:
const mongoose = require(‘mongoose’);
const router = require(‘express’).Router();
const Articles = mongoose.model(‘Articles’);
router.post(‘/’, (req, res, next) => {
const { body } = req;
if(!body.title) {
return res.status(422).json({
errors: {
title: ‘is required’,
},
});
}
if(!body.author) {
return res.status(422).json({
errors: {
author: ‘is required’,
},
});
}
if(!body.body) {
return res.status(422).json({
errors: {
body: ‘is required’,
},
});
}
const finalArticle = new Articles(body);
return finalArticle.save()
.then(() => res.json({ article: finalArticle.toJSON() }))
.catch(next);
});
router.get(‘/’, (req, res, next) => {
return Articles.find()
.sort({ createdAt: ‘descending’ })
.then((articles) => res.json({ articles: articles.map(article => article.toJSON()) }))
.catch(next);
});
router.param(‘id’, (req, res, next, id) => {
return Articles.findById(id, (err, article) => {
if(err) {
return res.sendStatus(404);
} else if(article) {
req.article = article;
return next();
}
}).catch(next);
});
router.get(‘/:id’, (req, res, next) => {
return res.json({
article: req.article.toJSON(),
});
});
router.patch(‘/:id’, (req, res, next) => {
const { body } = req;
if(typeof body.title !== ‘undefined’) {
req.article.title = body.title;
}
if(typeof body.author !== ‘undefined’) {
req.article.author = body.author;
}
if(typeof body.body !== ‘undefined’) {
req.article.body = body.body;
}
return req.article.save()
.then(() => res.json({ article: req.article.toJSON() }))
.catch(next);
});
router.delete(‘/:id’, (req, res, next) => {
return Articles.findByIdAndRemove(req.article._id)
.then(() => res.sendStatus(200))
.catch(next);
});
module.exports = router;
The routes we have created are:
POST localhost:8000/api/articles/ which expects a body like this:
{
“title”: “Test title”,
“author”: “Erdeljac”,
“description”: “Test desc”,
}
PATCH localhost:8000/api/articles/:id which expects a body like this:
{
“title”: “Test title”,
“author”: “Erdeljac”,
“description”: “Test desc”,
}
GET localhost:8000/api/articles which returns a list of all articles.
GET localhost:8000/api/articles/:id which returns a specific article.
Frontend (React)
Initial configuration (Webpack, package.json & dependencies)
Create a new folder alongside our server folder called client. Like this:
Inside our client folder run the following command in terminal:
npm init
And press enter on all questions, like this:
npm install –save-dev node-sass html-webpack-plugin style-loader sass-loader css-loader file-loader html-loader webpack webpack-dev-server webpack-cli babel babel-loader babel-plugin-transform-object-rest-spread babel-preset-env babel-preset-react
Due to compatibility issues run this command too:
npm i -D extract-text-webpack-plugin@next
After that let’s install other dependencies (not dev dependencies):
npm i -S react moment bootstrap babel-polyfill history prop-types react-dom react-redux react-router-dom react-scripts redux axios
Now create a file called webpack.config.js inside our /client folder.
const HtmlWebpackPlugin = require(‘html-webpack-plugin’);
const ExtractTextPlugin = require(‘extract-text-webpack-plugin’);
module.exports = {
entry: [
‘babel-polyfill’,
‘./src/index.js’,
],
output: {
publicPath: ‘/’,
filename: ‘./main.js’,
},
resolve: {
extensions: [‘.js’, ‘.jsx’],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [‘babel-loader’],
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: {
loader: ‘file-loader’,
options: {
name: ‘public/img/[name].[ext]’,
outputPath: ‘dist/img/’,
},
},
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: ‘style-loader’,
use: [{ loader: ‘css-loader’, options: { minimize: true } }, ‘sass-loader’],
}),
},
{
test: /\.html$/,
use: {
loader: ‘html-loader’,
options: {
minimize: true,
},
},
},
{
test: /\.(otf|ttf|eot|woff|woff2)$/,
loader: ‘file-loader’,
options: {
name: ‘public/fonts/[name].[ext]’,
outputPath: ‘dist/fonts’,
},
},
],
},
plugins: [
new ExtractTextPlugin({ filename: ‘style.css’ }),
new HtmlWebpackPlugin({
template: ‘./resources/index.html’,
filename: ‘./index.html’,
hash: true,
}),
],
devServer: {
historyApiFallback: true,
publicPath: ‘/’,
contentBase: ‘./dist’,
},
};
And then let’s create .babelrc:
{
“presets”: [“env”, “react”],
“plugins”: [“transform-object-rest-spread”]
}
Head over to package.json and edit the scripts object:
…
“scripts”: {
“test”: “echo \”Error: no test specified\” && exit 1″,
“build”: “webpack –mode production”,
“start”: “webpack-dev-server –mode development –open”
},
…
Create a new folder called resources and create an index.html file inside:
That’s all for configuration. We can now start creating react components. This is how your folder structure should look like:
React components
Inside our client folder create a folder called src and create a file index.js inside of it:
Now head over to terminal and run (in client dir):
npm start
If everything went fine you should get a result like this in your browser:
Setting up the router & App component
Let’s edit our index.js file:
Let’s create a components folder, then create index.js file inside of it.
export { default as App } from ‘./App’;
Now let’s create App component, start by creating a folder named App with index.jsx file inside of it: