Server-side pagination using ngx-pagination - node.js

I got the ngx-pagination module working with all the listings in the GET, but I want the pagination to work server-side too, but I'm unsure how to implement it further than what I have. I'm looking at the documentation for ngx-pagination, but I'm a little bit confused. Here's what I have.
html code
<body [ngClass]="[(this.isOpen && this.mobile) || (this.isOpen && this.tablet) ? 'hideContent' : 'showContent']">
<div class="loading">
<!-- <mat-spinner class="loader" *ngIf="isLoading"></mat-spinner> -->
<ngx-spinner id="loadingIcon" *ngIf="isLoading" type="cog" size="large" color="#3071a9">
<p class="loadingTitle">Loading...</p>
</ngx-spinner>
</div>
<div class="spacing"></div>
<div class="container">
<div class="row no-gutters"
*ngIf="!this.isOpen && this.mobile || this.isOpen && !this.mobile || !this.isOpen && !this.mobile">
<div class="class col-md-7"></div>
</div>
<!-- /|slice:0:show -->
<!--; let i = index-->
<div class="row"
*ngFor="let auction of posts | paginate: { itemsPerPage: 10, currentPage: p, totalItems: this.posts.count }">
<div class="col-md-12 col-centered">
<div class="listingCard" [#simpleFadeAnimation]="'in'">
<div class=container>
<div class="row">
<div class="col-md-3">
</div>
<div class="col-md-6">
<div id="title">{{auction.title}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<pagination-controls (pageChange)="p = $event"></pagination-controls>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body [ngClass]="[(this.isOpen && this.mobile) || (this.isOpen && this.tablet) ? 'hideContent' : 'showContent']">
<div class="loading">
<!-- <mat-spinner class="loader" *ngIf="isLoading"></mat-spinner> -->
<ngx-spinner id="loadingIcon" *ngIf="isLoading" type="cog" size="large" color="#3071a9">
<p class="loadingTitle">Loading...</p>
</ngx-spinner>
</div>
<div class="spacing"></div>
<div class="container">
<div class="row no-gutters"
*ngIf="!this.isOpen && this.mobile || this.isOpen && !this.mobile || !this.isOpen && !this.mobile">
<div class="class col-md-7"></div>
</div>
<!-- /|slice:0:show -->
<!--; let i = index-->
<div class="row"
*ngFor="let auction of posts | paginate: { itemsPerPage: 10, currentPage: p, totalItems: this.posts.count }">
<div class="col-md-12 col-centered">
<div class="listingCard" [#simpleFadeAnimation]="'in'">
<div class=container>
<div class="row">
<div class="col-md-3">
</div>
<div class="col-md-6">
<div id="title">{{listing.title}}</div>
</div>
</div>
</div>
=
</div>
</div>
</div>
</div>
<pagination-controls (pageChange)="p = $event"></pagination-controls>
</body>
.ts File component
p: number = 1;
ngOnInit(){
this.submitListingService.getListings(this.postsPerPage, this.currentPage);
this.listingService
.getPostUpdateListener()
.pipe(takeUntil(this.destroy))
.subscribe((postData: { listing: Listing[]; postCount: number }) => {
this.isLoading = false;
this.totalPosts = postData.postCount;
this.posts = postData.listing;
this.filteredPosts = postData.listing;
});
}
Angular service
getListings(postsPerPage: number, currentPage: number) {
let listings = "Get Listings";
const params = new HttpParams().set("listings", listings);
const queryParams = `?pagesize=${postsPerPage}&page=${currentPage}`;
this.http
.get<{ message: string; posts: any; maxPosts: number }>(
"http://localhost:3000/api/listings" + queryParams,
{ params }
)
.pipe(
map(postData => {
return {
posts: postData.posts.map(post => {
return {
title: post.title,
id: post._id
};
}),
maxPosts: postData.maxPosts
};
})
)
.pipe(takeUntil(this.destroy))
.subscribe(transformedPostData => {
this.posts = transformedPostData.posts;
this.postsUpdated.next({
listing: [...this.posts],
postCount: transformedPostData.maxPosts
});
});
}
-> Server Code
app.js
app.get("/api/listings", (req, res, next) => {
Post.find({ auctionEndDateTime: { $gte: Date.now() } })
.populate("creator", "username")
.then(documents => {
req.params.Id = mongoose.Types.ObjectId(req.params.Id);
res.status(200).json({
message: "Auction listings retrieved successfully!",
posts: documents
});
});
});

Here is another way to do this.
This might be a better fit for your case.
Post.find({ auctionEndDateTime: { $gte: Date.now() } })
.populate("creator", "username")
.then(documents => {
req.params.Id = mongoose.Types.ObjectId(req.params.Id);
let per_page = req.query.pagesize;
let page = req.query.page || 1;
let offset = (page - 1) * per_page;
res.status(200).json({
message: "Auction listings retrieved successfully!",
posts: documents.slice(offset).slice(0,
per_page)
});
});
and here is one more approach using slice
var skip = req.query.pagesize * (req.query.page - 1)
Post.where('auctionEndDateTime').gte(Date.now()).slice([skip, req.query.pagesize])
.populate("creator", "username")
.then(documents => {
res.status(200).json({
message: "Auction listings retrieved successfully!",
posts: documents
});
})

You will need two values on server side one is page i.e. which page number to show and second is limit i.e. how many results to show on the page.
Then just use:
.skip(limit * (page - 1)).limit(limit)
First operator will skip the unwanted results for eg: if page is 2 and limit is 20 then in first operation the first 20 results will be skipped then in second operation we will limit the result to 20 results so you will get documents 21 to 40 which is desired result.

Your Service File ,
getListings(postsPerPage: number, currentPage: number) {
// let listings = "Get Listings";
// const params = new HttpParams().set("listings", listings);
// const queryParams = `?pagesize=${postsPerPage}&page=${currentPage}`;
const queryParams = postsPerPage+"/"+currentPage; //change this .
this.http
.get<{ message: string; posts: any; maxPosts: number }>(
"http://localhost:3000/api/listings/" + queryParams
)
.pipe(
map(postData => {
return {
posts: postData.posts.map(post => {
return {
title: post.title,
id: post._id
};
}),
maxPosts: postData.maxPosts
};
})
)
.pipe(takeUntil(this.destroy))
.subscribe(transformedPostData => {
this.posts = transformedPostData.posts;
this.postsUpdated.next({
listing: [...this.posts],
postCount: transformedPostData.maxPosts
});
});
}
As you are sending parameters so you need to change the URL of API as below i mentioned in server code ,
Your Server code will be as follow ,
app.get("/api/listings/:postPerPage/:currentPage", (req, res, next) => {
let postPerPage = req.params.postPerPage;
let currentPage = req.params.currentPage;
Post.find({ auctionEndDateTime: { $gte: Date.now() } })
.populate("creator username")
.skip(postPerPage * currentPage)
.limit(postPerPage)
.then(documents => {
req.params.Id = mongoose.Types.ObjectId(req.params.Id);
res.status(200).json({
message: "Auction listings retrieved successfully!",
posts: documents
});
});
});
From the above code you will get the post equals to postPerPage .
Hope this is what you looking for . Thank you

Related

React - Display product in Cart one row per id/quantity

I've got a React App, that scans products via a Scanner(using serialport.io + socket.io) and adds each scanned product into my frontend cart component.
Right now I got it working, but my solution creates a new row in my cart per product scanned as you can see here and I need it to display a new row only the first time a prod is scanned and then if the same product is detected it only updates the quantity and total per product and also the cart total, something like this...
From what I've searched the best way to do this would be by using react useContext and useReducer but I can't get it working.
This is my code on server side index.js:
io.on("connection", (socket) => {
console.log("Socket Connected");
const port = new SerialPort({
path: "COM6",
baudRate: 9600,
autoOpen: false,
});
socket.on("start_scanner", () => {
port.open(function (err) {
if (err) {
console.log("Error opening port: ", err.message);
}
else{
console.log("Scanner Connected");
}
});
port.on("open", function () {
setInterval(function () {
const portReader = port.read();
if (portReader != null) {
const sensorVal = Buffer.from(portReader).toString();
const soap = require("soap");
const url = "http://example.com?wsdl";
soap.createClient(url, function (err, client) {
client.GetProductById(
{
UserId: "1",
ProductId: sensorVal,
},
function (err, result) {
if (err) return console.log(err);
let productScanned = result.GetProductByIdResult;
socket.broadcast.emit("add_product_to_list", productScanned);
}
);
});
}
}, 700);
});
});
This is my Cart component code:
import { useState, useEffect } from "react";
import io from "socket.io-client";
import ProductRow from "./ProductRow";
import "./ProductsList.css";
const socket = io.connect("http://localhost:5000");
const ProductsList = (props) => {
const [scannedData, setScannedData] = useState([]);
useEffect(() => {
socket.on("add_product_to_list", (productScanned) => {
setScannedData((prevProducts) => [...prevProducts, productScanned]);
});
}, [socket]);
return (
<div className="w-9/12 h-full px-20 py-20 flex flex-col ">
<div className="w-full h-auto my-2 px-3 py-3 font-semibold grid grid-cols-3 bg-blue-600 rounded-xl">
<div className="w-[60%] text-left">Product</div>
<div className="w-[20%] text-left">Quant.</div>
<div className="w-[20%] text-left">Price</div>
</div>
<div
id="products-wrapper"
className="w-full h-[95%] flex flex-col overflow-x-hidden overflow-y-scroll"
>
{scannedData.map((productScanned) => (
<ProductRow data={productScanned} />
))}
</div>
<div className="w-full h-[15%] flex flex-row justify-end">
<div className="w-[20%] h-auto px-3 py-3 font-semibold flex flex-col justify-center bg-blue-600 rounded-xl ">
<div className="w-full text-left">
Total: {/* Total price amount */}{" "}
</div>
<div className="w-full text-left">
Qty: {0}
</div>
</div>
</div>
</div>
);
};
export default ProductsList;
This is my Cart Row component:
import "./ProductsList.css";
const ProductRow = ({ data }) => {
return (
<div
className="product-row w-full h-auto my-2 px-3 py-3 text-black text-center grid grid-cols-3 rounded-xl "
key={data._x003C_Id_x003E_k__BackingField}
>
<div className="w-[60%] text-left">
{data._x003C_Name_x003E_k__BackingField}
</div>
<div className="w-[20%] text-left">{1}</div>
<div className="w-[20%] text-left">
{parseFloat(data._x003C_Price_x003E_k__BackingField).toFixed(2)}€
</div>
</div>
);
};
export default ProductRow;
I've also got a cart-context.js and a CartProvider.js files which I was using to achieve my goal but can't get it to work.
/*cart-context.js*/
import React from "react";
const CartContext = React.createContext({
items: [],
totalAmount: 0,
addItem: (item) => {},
removeItem: (id) => {},
});
export default CartContext;
/*CartProvider.js*/
import { useContext, useReducer } from "react";
import CartContext from "./cart-context";
const defaultCartState = {
items: [],
totalAmount: 0,
};
const cartReducer = (state, action) => {
if (action.type === "ADD_ITEM") {
const updatedTotalAmount = state.totalAmount + action.item.price * action.item.amount;
const existingCartItemIndex = state.items.findIndex(
(item) => item.id === action.item.id
)
const existingCartItem = state.items[existingCartItemIndex];
let updatedItems;
if(existingCartItem){
const updatedItem = {
...existingCartItem,
amount: existingCartItem.amount + action.item.amount
}
updatedItems = [...state.items];
updatedItems[existingCartItemIndex] = updatedItem;
} else{
updatedItems = state.items.concat(action.item);
}
return {
items: updatedItems,
totalAmonut: updatedTotalAmount,
};
}
return defaultCartState;
};
const CartProvider = (props) => {
const [cartState, dispatchCartAction] = useReducer(
cartReducer,
defaultCartState
);
const addItemToCartHandler = (item) => {
dispatchCartAction({ type: "ADD_ITEM", item: item });
};
const removeItemFromCartHandler = (id) => {
dispatchCartAction({ type: "REMOVE_ITEM", id: id });
};
const cartContext = {
items: cartState.items,
totalAmonut: cartState.totalAmonut,
addItem: addItemToCartHandler,
removeItem: removeItemFromCartHandler,
};
return (
<CartContext.Provider value={cartContext}>
{props.children}
</CartContext.Provider>
);
};
export default CartProvider;
Could anyone help me out and help me understand my mistakes?
Thanks in advance.

Can not load array from backend

After a search, I am sending the result to frontend in the form of array. But I am not being able to get that array in frontend using fetch. Through postman I am able to get the result from the backend but I am not able to get it in the frontend. In another file, I have set axios.post as well and exported from there and imported in frotend.
I am beginner so I might have written a bad code, any help will mean a lot.
In frontend :
class Hostel extends Component{
constructor (){
super();
this.state = {
country : '',
city : '',
category : '',
errors : {}
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
this.setState({
errors: nextProps.errors
});
}
}
onChangeAddOptions = e => {
this.setState({ [e.target.id]: e.target.value });
};
addOption = e => {
e.preventDefault();
const newOption = {
country : this.state.country,
city : this.state.city,
category:this.state.category,
}
this.props.saveOptions(newOption,this.props.history);
};
getHostels = async ()=> {
console.log("getHostel function is called");
const response = await fetch('http://localhost:5000/api/users/hostel',{
method : "POST",
// headers:{
// "Content-Type" : "application/json"
// },
})
.then((response)=> {response.json()})
.then((data)=>{
console.log("inside data");
console.log(data);
})
.catch(e=>{
console.error(e.error);
})
console.log("From outside of data");
console.log(response);
}
componentDidMount(){
this.getHostels();
}
render (){
const {errors,country,city,category} = this.state;
return(
<section className="Hosteldashboard">
<div className="left_container">
<h2>Yo che left section</h2>
<div>
<form noValidate onSubmit={this.addOption}>
<div class="form-row">
<label htmlFor="country">Country</label> <br />
<input
type="text"
className="input-control"
placeholder="Country name"
id="country"
value={country}
onChange={this.onChangeAddOptions}
error={errors.country}
className={classnames('', {
invalid: errors.country
})}
/>{' '}
<br />
<span className="text-danger">{errors.country}</span>
</div>
<div class="form-row">
<label htmlFor="city">City</label> <br />
<input
type="text"
className="input-control"
placeholder="City name"
id="city"
value={city}
onChange={this.onChangeAddOptions}
error={errors.city}
className={classnames('', {
invalid: errors.city
})}
/>{' '}
<br />
<span className="text-danger">{errors.city}</span>
</div>
<div class="form-row">
<label htmlFor="category">Category</label> <br />
<input
type="text"
className="input-control"
placeholder="Boys or Girls"
id="category"
value={category}
onChange={this.onChangeAddOptions}
error={errors.category}
className={classnames('', {
invalid: errors.category
})}
/>{' '}
<br />
<span className="text-danger">{errors.category}</span>
</div>
<div>
<button type="submit" className = "searchHostel" onClick={this.getHostels}>
Search
</button>
</div>
</form>
</div>
</div>
In backend :
router.post('/hostel',async (req,res)=>{
try{
console.log(req.body);
const {
errors,
isValid
} = validateSearchHostelInput(req.body);
//Check Validation
// if (!isValid){
// return res.status(400).json(errors);
// }
const page = parseInt(req.query.page) - 1 || 0;
const limit = parseInt(req.query.limit) || 5;
const search = req.query.search || "";
let sort = req.query.sort || "price";
let category = req.query.category || "All";
const categoryOptions = [
req.body.country,
req.body.city,
req.body.category
]
category === "All"
? (category = [...categoryOptions])
: (category = req.query.category.split(","));
req.query.sort ? (sort = req.query.sort.split(",")) : (sort = [sort]);
let sortBy = {};
if(sort[1]) {
sortBy[sort[0]] = sort[1];
} else {
sortBy[sort[0]] = "asc";
}
const hostel = await Hostel.find({title: {$regex: search, $options: "i"}})
.where("category")
.in([...category])
.sort(sortBy)
.skip(page * limit)
.limit(limit);
// const total = await Hostel.countDocuments({
// category: {$in: [...category]},
// title: { $regex: search, $options: "i"},
// });
// const response = {
// error: false,
// total,
// page: page + 1,
// limit,
// categories: categoryOptions,
// hostel
//}
console.log("From Hostel : " + hostel);
res.status(200).json({hostel:hostel});
}catch(err){
console.log(err);
res.status(500).json({error:true,message:"Internal Server Error"});
}
});
module.exports = router;

TypeError: Cannot read property 'length' of null. The functionality was working recently but suddenly this error appears

I am using this same search functionality on the production server and it is working there fine. Suddenly this error appears as I used it on a development server. Also, I observed that the backend code showing status code 200 when I searched a query in the search box and submit it. The below-shown code is the code that I wrote on the frontend and backend. What can be the problem
backend code:
exports.listSearch =async (req, res) => {
try {
const { search } = req.query;
if (search) {
await Job.find(
{
$or: [{ title: { $regex: search, $options: 'i' } ,body: { $regex: search, $options: 'i' },location: { $regex: search, $options: 'i' }}]
},
(err, jobs) => {
if (err) {
return res.status(400).json({
error: errorHandler(err)
});
}
res.json(jobs);
}
).select('-photo -body').sort({updatedAt:-1});
}
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
Front end code:
import Link from 'next/link';
import React,{ useState } from 'react';
import { listSearchPvt } from '../../actions/privateJob';
const SearchPvt = () => {
const [values, setValues] = useState({
search: undefined,
results: [],
searched: false,
message: '',
});
const { search, results, searched, message, } = values;
const searchSubmit = e => {
e.preventDefault();
listSearchPvt({ search }).then(data => {
setValues({ ...values, results: data, searched: true, message: `${data.length} jobs found` });
});
};
const handleChange = e => {
setValues({ ...values, search: e.target.value, searched: false, results: [] });
};
const searchedJobs = (results = []) => {
return (
<div className="bg-light">
{message && <p className="extra-small text-light-gray " >{message}</p>}
{results.map((privateJob, i) => {
return (
<div key={i} >
<Link href={`/privateJobs/${privateJob.slug}`}>
<a>
<h3 className="text-dark " style={{fontFamily:`'Source Serif Pro' ,serif` ,lineHeight:'1.9rem'}}>
🤩<span> </span>{privateJob.title}
</h3>
<div className="line"></div>
</a>
</Link>
</div>
);
})}
</div>
);
};
const searchForm = () => (
<form onSubmit={searchSubmit} style={{width: '100%', display: 'flex' ,alignItems:'end' ,height: '2.4rem',justifyContent:'space-between',alignContent:'center',alignItems:'center' }} className="btn nbtn btn-success" >
<input className='btn nbtn btn-success' style={{width:'100%'}} type="search" placeholder="Search Jobs" onChange={handleChange} />
<button className="btn nbtn btn-dark lead my-1" type="submit" >Search</button>
</form>
);
return (
<>
<div style={{display:'block'}}>
<div className="my-3">{searchForm()}</div>
{searched && <div className='blog m-2 ' >{searchedJobs(results)}</div>}
</div>
</>
);
}
export default SearchPvt;

I want to create a Search method that autodisplay some results

I'm creating a function that is looking for users in database.
I've done the server-side code, but I don't know how to display the results in the html code. I know that I have to write some JavaScript code but I don't know how
I found something on Google, but it doesn't work.
This is my route.
router.get('/search', isAuth, feedController.getSearch);
This is my controller.
exports.getSearch = (req,res,next) => {
const search = req.query.searchField;
User.find({
firstname:{
$regex: new RegExp(search)
},
}, {
_id:0,
__v:0
}, function (err,data) {
res.json(data);
}
).limit(10);
}
This is my HTML
<li>
<div class="search-box">
<form action="/search" method="GET" class="form-inline my-0 my-lg-0">
<input type="text" aria-label="Search" class="form-control mr-sm-0" onkeyup="showResults(this.value)" placeholder="Mirror-Mirror Search">
<span class="hightlight"></span>
<span class="bar"></span>
</input>
<button type="submit" class="search-btn"><i class="fas fa-search"></i></button>
</form>
</div>
<div style="position: relative; width:100%; top:-1px;">
<div class="border" id="search-results"></div>
</div>
</li>
And this is what I found on Google
var showResults = debounce(function(arg) {
var value = arg.trim();
if(value == "" || value.length <=0)
{
$("#search-results").fadeOut();
return;
}
else {
$("#search-results").fadeIn();
}
var jgxh = $.get('/controllers/feed/getSearch?searchField=' + value, function(data) {
$("#search-results").html("");
})
.done(function(data){
if(data.length === 0) {
$("#search-results").append('<p class="lead text-center mt-2">No results</p>');
} else {
data.forEach(x => {
$("#search-results").append('<a href="#> <p class="m-2 lead>' +x.firstname+' '+x.lastname + '</p></a>')
});
}
})
.fail(function(err){
console.log(err);
})
},200)
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this;
args = arguments;
var later = function () {
timeout = null;
if(!immediate) func.apply(context,args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if(callNow) func.apply(context,args);
};
};
I expected to autodisplay the results, but It doesn't work. I want to search in my database either for 'firstname' or 'lastname', I hope you can help me, thank you!

Reactjs - setState doesn't re-render after update

Simply all i'm trying to do is re render the notes list when i add another note to the database. i tried several methods even redux dispatch method. but none worked and it kinda make sense because when i add a note i don't add anything so it can get the updated notes through /budget. maybe i have a big misunderstanding.
here's how i add a new note
export function saveOneNote() {
// saving a note
const _id = $('input[name="_id"]').val(),
firstItem = $('input[name="firstItem"]').val(),
firstPrice = $('input[name="firstPrice"]').val(),
secondItem = $('input[name="secondItem"]').val(),
secondPrice = $('input[name="secondPrice"]').val(),
thirdItem = $('input[name="thirdItem"]').val(),
thirdPrice = $('input[name="thirdPrice"]').val(),
tBudget = $('input[name="tBudget"]').val();
let currency = $("#currency").val();
console.log(currency);
$.ajax({
url: "/newNote",
type: "post",
dataType: "json",
contentType: "application/json",
data: JSON.stringify({
currency,
_id,
firstItem,
firstPrice,
secondItem,
secondPrice,
thirdItem,
thirdPrice,
tBudget
}),
success: function(Data) {
console.log("note was saved!", Data);
},
error: function(err, status, xhr) {
console.log("err", err);
}
});
}
here's how i fetch notes
class ShowAll extends Component {
constructor(props){
super(props);
this.state = {
Data: [],
length:[],
searchbyid:[],
isLoggedIn:[]
}
}
componentDidMount(){
// fetch notes
Rquest.get('/budget').then((res)=>{
let DataString = Array.from(res.body);
this.setState((prevState,props)=>{
return {
Data: DataString,
length: res.body.length
}
})
}).catch((err)=> {
console.log(err);
})
// check if user is logged in
Request.get('/auth').then((user)=>{
if(user){
this.setState({
isLoggedIn: true
})
}
}).catch((err)=> {
this.setState({
isLoggedIn: false
})
});
}
render(){
const count = this.state.length;
const myNotes = this.state.Data;
const isLoggedIn = this.state.isLoggedIn;
const listItems = myNotes.map((dynamicData)=>{
return(
<Fragment key={dynamicData.id}>
<div className='jumbotron'>
<div className='row'>
<button className='btn btn-danger delete-note-btn' onClick={DeleteOneNote}>Delete</button>
<input className='col-12 title form-control' id='deleteById' value={dynamicData._id} readOnly/>
<div className="dropdown-divider"></div> {/*line divider*/}
<div className='col-6' >
<ul className='list-unstyled'>
<li className='items'>items</li>
<li >{dynamicData.firstItem}</li>
<li >{dynamicData.secondItem}</li>
<li >{dynamicData.thirdItem}</li>
{/* <li>Total Budget :</li> */}
</ul>
</div>
<div className='dynamicData col-6'>
<ul className ='list-unstyled'>
<li className='prices'>Prices</li>
<li>{dynamicData.firstPrice} {dynamicData.currency}</li>
<li>{dynamicData.secondPrice} {dynamicData.currency}</li>
<li>{dynamicData.thirdPrice} {dynamicData.currency}</li>
</ul>
</div>
</div>
<h3 className='col-12 totalprice'>{dynamicData.tBudget} {dynamicData.currency}</h3>
</div>
</Fragment>
)
})
return (
<Fragment>
{isLoggedIn ===true?(
<div className='myNotesList '>
number of notes : {count}
{listItems}
</div>
):(
<Fragment>
</Fragment>
)
}
</Fragment>
)
}
}
React components are re-rendering only on state or props change. In your code - you're not mutating state nor props of your component.
What you should do in your case probably is to re-fetch the items after save or add the new items to the state or pass through props.
Example:
class Notes extends React.Component {
state = { note: '', notes: [] }
changeNote = ({ target: { value } }) => {
this.setState({ note: value });
}
addNote = () => {
this.setState((state) => ({ notes: [...state.notes, state.note] }));
}
render() {
return (
<div>
<input type="text" onChange={this.changeNote} />
<button onClick={this.addNote}>Add</button>
<ul>
{this.state.notes.map(note =>
<li>{note}</li>
)}
</ul>
</div>
)
}
}
ReactDOM.render(
<Notes />,
document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.production.min.js"></script>
<div id="app">
</div>

Resources