how to delete a row in table in reactjs - javascript

I'm trying to implement a delete operation on table rows. but it keeps on throwing errors. So I need some help to figure this out.
I don't know to how to set id that can be auto incremented so I gave Date.now().
now what I want is to delete the row that i perform the delete operation on.
I'm new to react so sorry for the bad code. thank you in advance.
heres my code
import React from "react";
import { CirclesWithBar } from "react-loader-spinner";
import { useState } from "react";
import Table from "./Table";
function Main() {
// *****INITIALIZING*****
const [tableData, setTableData] = useState([])
const [formInputData, setformInputData] = useState(
{
id: Date.now(),
Name: '',
email: '',
}
);
const [loading, setloading] = useState(false);
// const deleteTableRows = (index)=>{
// const rows = [...rowsData];
// rows.splice(index, 1);
// setTableData(rows);
// }
// **********DECLARING FUNCTIONS*********
const handleChange = (evnt) => {
const newInput = (data) => ({ ...data, id: Date.now(), [evnt.target.name]: evnt.target.value })
setformInputData(newInput)
}
const handleSubmit = (evnt) => {
evnt.preventDefault();
setloading(true)
const checkEmptyInput = !Object.values(formInputData).every(res => res === "")
if (checkEmptyInput) {
const newData = (data) => ([...data, formInputData])
setTableData(newData);
const emptyInput = { id: '', Name: '', email: '' }
setformInputData(emptyInput)
}
setTimeout(() => {
setloading(false)
}, 1000)
}
const singleDelete = (event) => {
event.preventDefault();
setloading(true)
const handleDelete = (id) => {
const newArr = [...tableData];
console.log(tableData);
const index = setTableData.findIndex((data) => data.name(id) === id);
console.log(index);
newArr.splice(index, 1);
setTableData(newArr);
}
setTimeout(() => {
setloading(false)
}, 1000)
}
// ************RETURNING VALUES************
return (
<div className="container">
<div className="row">
<div className="col-sm-8">
<div className="col">
<input type="text" onChange={handleChange} value={formInputData.Name} name="Name" className="form-control" placeholder="Name" />
</div>
<div className="col">
<input type="email" onChange={handleChange} value={formInputData.email} name="email" className="form-control" placeholder="Email Address" />
</div>
<div className="col">
<input type="submit" onClick={handleSubmit} className="btn btn-success" />
{
loading ?
<CirclesWithBar
height="75"
width="100"
color="#002B5B"
wrapperStyle={{}}
wrapperClass=""
visible={true}
alignSelf='center'
outerCircleColor=""
innerCircleColor=""
barColor=""
ariaLabel='circles-with-bar-loading' loading={loading} size={50} />
:
<div>
{
<table className="table" id='table'>
<thead>
<tr>
<th>S.N</th>
<th>ID</th>
<th>Full Name</th>
<th>Email Address</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{
tableData.map((data, index) => {
return (
<tr>
<td>{index + 1}</td>
<td>{data.id}</td>
<td>{data.Name}</td>
<td>{data.email}</td>
<td><button value={data.id} onClick={() => singleDelete(data.id)} className="btn btn-danger">Delete</button></td>
</tr>
)
})
}
</tbody>
</table>
}
</div>
}
</div>
</div>
</div>
</div>
);
}
export default Main;

First, the error happens because you don't pass the click event parameter to the function.
It should be like that.
(e) => singleDelete(e, data.id)
Second, You can just use filter method to delete the item by add a condition any element that doesn't have this id.
const singleDelete = (event, id) => {
event.preventDefault();
setloading(true);
setTableData((prev) => prev.filter((i) => i.id !== id));
setTimeout(() => {
setloading(false);
}, 1000);
};
This is a full example of code.
import React from "react";
import { CirclesWithBar } from "react-loader-spinner";
import { useState } from "react";
function Main() {
// *****INITIALIZING*****
const [tableData, setTableData] = useState([]);
const [formInputData, setformInputData] = useState({
id: Date.now(),
Name: "",
email: ""
});
const [loading, setloading] = useState(false);
// const deleteTableRows = (index)=>{
// const rows = [...rowsData];
// rows.splice(index, 1);
// setTableData(rows);
// }
// **********DECLARING FUNCTIONS*********
const handleChange = (evnt) => {
const newInput = (data) => ({
...data,
id: Date.now(),
[evnt.target.name]: evnt.target.value
});
setformInputData(newInput);
};
const handleSubmit = (evnt) => {
evnt.preventDefault();
setloading(true);
const checkEmptyInput = !Object.values(formInputData).every(
(res) => res === ""
);
if (checkEmptyInput) {
const newData = (data) => [...data, formInputData];
setTableData(newData);
const emptyInput = { id: "", Name: "", email: "" };
setformInputData(emptyInput);
}
setTimeout(() => {
setloading(false);
}, 1000);
};
const singleDelete = (event, id) => {
event.preventDefault();
setloading(true);
setTableData((prev) => prev.filter((i) => i.id !== id));
setTimeout(() => {
setloading(false);
}, 1000);
};
// ************RETURNING VALUES************
return (
<div className="container">
<div className="row">
<div className="col-sm-8">
<div className="col">
<input
type="text"
onChange={handleChange}
value={formInputData.Name}
name="Name"
className="form-control"
placeholder="Name"
/>
</div>
<div className="col">
<input
type="email"
onChange={handleChange}
value={formInputData.email}
name="email"
className="form-control"
placeholder="Email Address"
/>
</div>
<div className="col">
<input
type="submit"
onClick={handleSubmit}
className="btn btn-success"
/>
{loading ? (
<CirclesWithBar
height="75"
width="100"
color="#002B5B"
wrapperStyle={{}}
wrapperClass=""
visible={true}
alignSelf="center"
outerCircleColor=""
innerCircleColor=""
barColor=""
ariaLabel="circles-with-bar-loading"
loading={loading}
size={50}
/>
) : (
<div>
{
<table className="table" id="table">
<thead>
<tr>
<th>S.N</th>
<th>ID</th>
<th>Full Name</th>
<th>Email Address</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{tableData.map((data, index) => {
return (
<tr>
<td>{index + 1}</td>
<td>{data.id}</td>
<td>{data.Name}</td>
<td>{data.email}</td>
<td>
<button
value={data.id}
onClick={(e) => singleDelete(e, data.id)}
className="btn btn-danger"
>
Delete
</button>
</td>
</tr>
);
})}
</tbody>
</table>
}
</div>
)}
</div>
</div>
</div>
</div>
);
}
export default Main;
This is working example with codesandbox.

Just modify your singleDelete function in this way -
const singleDelete = (id) => {
setloading(true);
const newTableData = tableData.filter(item => item.id !== id );
setTableData(newTableData)
setTimeout(() => {
setloading(false)
}, 1000)
}

Related

Passing user input from child functional component to parent functional component

Im creating an invoice generator where the user can add an item, its price, and the quantity. I want to access the user inputs as a state from a child functional component (TableItems.js) into a parent functional component (TableSheet.js) to be able to save the user inputs into a database preferably firestore. I'm having a problem accessing the user input value from the child component to the parent component. I have been struggling with this bug for days, i really hope you guys could help me.
This is the Child component
import React, {useState, useEffect} from 'react'
function TableItems({index, tableItem }) {
const [price, setPrice] = useState(0);
const [qty, setQty] = useState(0);
const [total, setTotal] = useState([]);
useEffect(() => {
//arithmetically add price and qty values
const x = Number(price) * Number(qty)
setTotal(x)
return () => {
//clean up function will be here
};
}, [price, qty, total ]);
return (
<>
<tr>
<td><input type='text' required/></td>
<td><input type='number' value={price} onChange={(e) => setPrice(e.target.value)}/></td>
<td><input type='number' value={qty} onChange={(e) => setQty(e.target.value)}/></td>
<td>{total}</td>
</tr>
</>
)
}
export default TableItems
This is the Parent component
import React, { useState } from 'react'
import TableItems from './TableItems'
function TableSheet() {
const [tableItem, setTableItem] = useState([1]);
//adding a new table cell (table row)
const addCell = () => {
setTableItem((t) => [...t, t + 1])
}
return (
<div>
<table>
<thead>
<th>Item Description</th>
<th>Price</th>
<th>Qty.</th>
<th>Total</th>
</thead>
{
tableItem.map((tableItem, index, setItem) => {
return <TableItems key={index} tableItem={tableItem} setItem={setItem} addCell={addCell}/>
})
}
</table>
<button onClick={addCell}>+</button>
</div>
)
}
export default TableSheet
You tableItem state should contains item objects (quantity and price)
TableItems
function TableItems({ index, tableItem, onChangeItem }) {
return (
<>
<tr>
<td>
<input type="text" required />
</td>
<td>
<input
type="number"
value={tableItem.price}
onChange={(e) => onChangeItem(index, "price", e.target.value)}
/>
</td>
<td>
<input
type="number"
value={tableItem.quantity}
onChange={(e) => onChangeItem(index, "quantity", e.target.value)}
/>
</td>
<td>{Number(tableItem.price) * Number(tableItem.quantity)}</td>
</tr>
</>
);
}
TableSheet
function TableSheet() {
const [tableItem, setTableItem] = useState([
{
price: 0,
quantity: 0
}
]);
const onChangeItem = (index, type, value) => {
const newTable = tableItem.map((item, idx) => {
if (idx === index)
return {
...item,
[type]: value
};
return item;
});
setTableItem(newTable);
};
const addCell = () => {
setTableItem((t) => [
...t,
{
price: 0,
quantity: 0
}
]);
};
const totalPrice = tableItem.reduce((acc, cur) => {
acc += Number(cur.price) * Number(cur.quantity);
return acc;
}, 0);
return (
<div>
<table>
<thead>
<th>Item Description</th>
<th>Price</th>
<th>Qty.</th>
<th>Total</th>
</thead>
{tableItem.map((tableItem, index) => {
return (
<TableItems
key={index}
index={index}
tableItem={tableItem}
onChangeItem={onChangeItem}
/>
);
})}
</table>
<button onClick={addCell}>+</button>
<div>Total: {totalPrice}</div>
</div>
);
}
you can check in my codesandbox. Hope it help!

React.js POST method issue

I'm doing this React.js project and I have to use POST method. I've managed to make the item appear in the the console and in the json file, but it's not showing in my table. I assume It has to do something with the useEffect hook, but since I'm very new to all of this, I don't know how to implement it correctly.
Table
import React, { useState, useEffect } from "react";
import axios from "axios";
const Table = () => {
//FETCH API
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
const fetchPosts = async () => {
setLoading(true);
const res = await axios.get("http://localhost:3000/movies");
setPosts(res.data);
setLoading(false);
};
fetchPosts();
}, []);
//SORTING
const [order, setOrder] = useState("ascending");
const sorting = (s) => {
if (order === "ascending") {
const sorted = [...posts].sort((a, b) =>
a[s].toLowerCase() > b[s].toLowerCase() ? 1 : -1
);
setPosts(sorted);
setOrder("descending");
}
if (order === "descending") {
const sorted = [...posts].sort((a, b) =>
a[s].toLowerCase() < b[s].toLowerCase() ? 1 : -1
);
setPosts(sorted);
setOrder("ascending");
}
};
//TABLE
return (
<div className="container">
<table className="table table-bordered table-striped">
<thead>
<tr>
<th className="click" onClick={() => sorting("name")}>
Name
</th>
<th>Genre</th>
<th>Rating</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{posts.map((post) => (
<tr key={post}>
<td>{post.name}</td>
<td>{post.genre}</td>
<td>{post.rating}</td>
<td>
{<button className="btn btn-outline-success">delete</button>}
{<button className="btn btn-outline-warning">edit</button>}
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
export default Table;
AddForm
import React from "react";
import { useState } from "react";
function AddForm() {
const [name, setName] = useState("");
const [genre, setGenre] = useState("");
const [rating, setRating] = useState("");
const handleSubmit = (e) => {
fetch("http://localhost:3000/movies", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: name,
genre: genre,
rating: rating,
}),
})
.then((response) => response.json())
.then((response) => {
console.log(response);
});
e.preventDefault();
};
return (
<div className="text-center">
<h2>Add a New movie</h2>
<form onSubmit={handleSubmit}>
<label>Name:</label>
<input
name="name"
type="text"
required="required"
onChange={(e) => setName(e.target.value)}
/>
<label>Genre:</label>
<input
name="genre"
type="text"
required="required"
onChange={(e) => setGenre(e.target.value)}
/>
<label>Rating:</label>
<input
name="rating"
type="text"
required="required"
onChange={(e) => setRating(e.target.value)}
/>
<button type="submit">Add</button>
</form>
</div>
);
}
export default AddForm;

tried a lot but not able to make deletehandler function working. here is my code

This is my librarylist component in which i pass deletehandler function to delete the row from library management. I don't know which part of the code is causing the problem. Any helps/suggestions are welcome.
LibraryBookList.js
const LibraryBookList = (props) => {
const[database, setDatabase]=useState()
const deleteHandler = (bookdataId) => {
const newDatabase=[...database];
const index= database.findIndex((bookdata)=>bookdata.id===bookdataId)
newDatabase.splice(index,1)
setDatabase(newDatabase);
} ;
return (
<ul className={classes.list}>
{props.database.map((bookdata) =>
(<LibraryBook
key={bookdata.key}
id={bookdata.id}
bookname={bookdata.bookName}
author={bookdata.author}
publisher={bookdata.publisher}
pages={bookdata.pages}
serialno={bookdata.serialNo}
onSelect={deleteHandler}
/>
))}
</ul>
)};
here i pass deletehandler via props
LibraryBook.js
const LibraryBook = (props) => {
return (
<li>
<table className={classes.table}>
<tbody>
<tr className={classes.table_row}>
<td className={classes.row_data}>{props.serialno}</td>
<td className={classes.row_data}>{props.pages}</td>
<td className={classes.row_data}>{props.bookname}</td>
<td className={classes.row_data}>{props.author}</td>
<td className={classes.row_data}>{props.publisher}</td>
<td>
<button className={classes.delete_btn} onClick={(props.onSelect(props.id))}>
Delete
</button>
</td>
</tr>
</tbody>
</table>
</li>
export default LibraryBookList;
**BookData.js **
const BookData = (props) => {
const [isLoading, setIsLoading] = useState(true);
const [loadedLibrarydata, setLoadedLibrarydata] = useState();
useEffect(() => {
setIsLoading(true);
fetch(
"https://librarymanagement-70ab2-default-rtdb.firebaseio.com/database.json"
)
.then((response) => {
// console.log('response',response.json())
return response.json();
})
.then((data) => {
const database = [];
console.log("data", data);
for (const key in data) {
const bookdata = {
id: key,
...data[key],
};
database.push(bookdata);
}
setIsLoading(false);
setLoadedLibrarydata(database);
});
}, []);
if (isLoading) {
return (
<section>
<p>Loading.....</p>
</section>
);
}
return (
<section>
<h1>Book Data Base</h1>
<table className={classes.table}>
<thead>
<tr className={classes.table_row}>
<th className={classes.row_heading}>Serial No</th>
<th className={classes.row_heading}>Pages</th>
<th className={classes.row_heading}>Book Name</th>
<th className={classes.row_heading}>Author</th>
<th className={classes.row_heading}>Publisher</th>
</tr>
</thead>
</table>
{loadedLibrarydata && loadedLibrarydata.length && (
<LibraryBooklist database={loadedLibrarydata} />
)}
</section>
);
};
export default BookData;
NewDataBase.js
const NewDataBase = () => {
const history=useHistory();
const addDataHandler = (bookData) => {
console.log('bookData',bookData);
fetch(
"https://librarymanagement-70ab2-default-rtdb.firebaseio.com/database.json",
{
method: "POST",
body: JSON.stringify(bookData),
headers: {
"Content-type": "application/json",
},
}
).then(()=>{
history.replace('/')
})
};
return (
<section>
<DataBaseForm onAddNewData={addDataHandler} />
</section>
);
};
export default NewDataBase;
The code has a few issues: 1) props.onSelect(props.id) inside onClick. Instead you should give a referance to that function. 2) You didn't have anything in database state before you click delete button. That is why ... spread operator didn't work 3) You are displaying props.database instead of database state. That is way the changes didn't show up even after you deleted a bookdata. I also fixed some small issues. Now it is working perfectly:
// !! you can put all the code into one file and run for testing.
// !! I removed stylings as I didn't have the source
import {useState, useEffect} from 'react'
const LibraryBooklist = (props) => {
const[database, setDatabase]=useState(props.database)
const deleteHandler = (bookdataId) => {
const newDatabase=database.filter((bookdata)=>bookdata.id!==bookdataId);
setDatabase(newDatabase);
}
return (
<ul>
{database.map((bookdata) =>
<LibraryBook
key={bookdata.id}
id={bookdata.id}
bookname={bookdata.bookName}
author={bookdata.author}
publisher={bookdata.publisher}
pages={bookdata.pages}
serialno={bookdata.serialNo}
onSelect={deleteHandler}
/>
)}
</ul>
)};
const LibraryBook = (props) => {
const {id, onSelect} = props
return (
<li>
<table>
<tbody>
<tr>
<td>{props.serialno}</td>
<td>{props.pages}</td>
<td>{props.bookname}</td>
<td>{props.author}</td>
<td>{props.publisher}</td>
<td>
<button onClick={() => onSelect(id)}>
Delete
</button>
</td>
</tr>
</tbody>
</table>
</li>
)}
const BookData = (props) => {
const [isLoading, setIsLoading] = useState(true);
const [loadedLibrarydata, setLoadedLibrarydata] = useState();
useEffect(() => {
setIsLoading(true);
fetch(
"https://librarymanagement-70ab2-default-rtdb.firebaseio.com/database.json"
)
.then((response) => {
// console.log('response',response.json())
return response.json();
})
.then((data) => {
const database = [];
for (const key in data) {
const bookdata = {
id: key,
...data[key],
};
database.push(bookdata);
}
setIsLoading(false);
setLoadedLibrarydata(database);
});
}, []);
if (isLoading) {
return (
<section>
<p>Loading.....</p>
</section>
);
}
return (
<section>
<h1>Book Data Base</h1>
<table>
<thead>
<tr>
<th>Serial No</th>
<th>Pages</th>
<th>Book Name</th>
<th>Author</th>
<th>Publisher</th>
</tr>
</thead>
</table>
{loadedLibrarydata && loadedLibrarydata.length && (
<LibraryBooklist database={loadedLibrarydata} />
)}
</section>
);
};
export default BookData;

Content Editable stays the same after changing page

I'm doing a web app that fetchs some info from the service and displays it in a table. I'm also using pagination. The objective is to receive some data and let the user change it, some of the fields don't have info yet, and the user can add it. The problem is, in this last situation, if the field is null and the user puts some info, after changing page with pagination from react, if in the place of the changed cell its another empty field, the info will stay, although its a different object.
export default function Product() {
const [resources, setResourcesData] = useState<PaginatedList>();
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(5);
const [sortValue, setSortValue] = useState("ASC");
const [sortPropertyName, setSortPropertyName] = useState("key");
const [searchString, setSearchString] = useState("");
const [searchPropertyName, setSearchPropertyName] = useState("Key");
/*just some info i needed to get the project name*/
const location = useLocation();
const str = JSON.stringify(location.state).split('"');
const prod = str[3];
const fetchItem = async () => {
let resourcesData: PaginatedList;
const fetchProducts = await axios.get(${config.SERVER_URL}/Resources, {
params: {
project: prod,
pageIndex: currentPage,
pageCount: itemsPerPage,
sortPropertyName: sortPropertyName,
sortOrder: sortValue,
searchPropertyName: searchPropertyName,
searchString: searchString,
},
});
resources?.items.forEach(res => {
let td = document.getElementById(res.key + res.culture + "comment");
var div = td?.childNodes.item;
console.log(div);
});
resourcesData = fetchProducts.data;
setResourcesData(resourcesData);
};
const editString = async (resx: IResource) => {
let resource: IResource;
let value = document.getElementById(resx.key + "value")?.innerText;
let comment = document.getElementById(resx.key + "comment")?.innerText;
if (comment === undefined) {
comment = "";
}
if (value === undefined) {
value = "";
}
console.log(value);
resource = {
project: prod,
key: resx.key,
value: value,
comment: comment,
culture: resx.culture,
};
await axios.put(${config.SERVER_URL}/Update, resource);
};
const nextList = () => {
setCurrentPage(currentPage + 1);
};
const previousList = () => {
setCurrentPage(currentPage - 1);
};
const onChangePrev = () => {
if (currentPage == 1) {
return true;
}
return false;
};
const onChangeNext = () => {
if (currentPage == resources?.totalPages) {
checkUndefined();
return true;
}
return false;
};
const firstList = () => {
setCurrentPage(1);
};
const lastList = () => {
setCurrentPage(resources!.totalPages);
};
const handleSortValueChange = (
e: React.MouseEvent<HTMLImageElement, MouseEvent>
) => {
if (e.currentTarget.classList.contains("asc")) {
e.currentTarget.classList.remove("asc");
e.currentTarget.classList.add("desc");
setSortValue("DESC");
} else {
e.currentTarget.classList.remove("desc");
e.currentTarget.classList.add("asc");
setSortValue("ASC");
}
};
function checkUndefined() {
}
useEffect(() => {
fetchItem();
}, [
currentPage,
itemsPerPage,
sortValue,
searchString,
searchPropertyName,
sortPropertyName,
]);
/*
const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - indexOfLastItem;
*/
if (!resources?.items) {
return <div>Loading... </div>;
} else {
return (
<div className="App">
<div style={{ height: "5rem" }}></div>
<div className="styled-table">
<div className="div-grande">
<input
placeholder="Search"
type="text"
name="search"
id="search"
onChange={(s) => setSearchString(s.target.value)}
/>
<div className="radio-button">
Key
<label>
<input
type="radio"
value="key"
id="searchByKey"
checked={"key" === searchPropertyName}
onClick={(n) => setSearchPropertyName("key")}
/>
</label>
Value
<label>
<input
type="radio"
value="value"
name="searchByValue"
checked={"value" === searchPropertyName}
onClick={(n) => setSearchPropertyName("value")}
/>
</label>
</div>
<div className="div-arrow">
<img
data-testid="sortValue"
id="sortImage"
className="asc"
src="/arrow.svg"
alt="sort"
title={
sortValue
? "Press to ascending order"
: "Press to descending order"
}
onClick={handleSortValueChange}
/>
Order by:
<Select
className="select-order"
isSearchable={false}
closeMenuOnSelect={true}
id="order"
options={[
{ label: "Key", value: "Key" },
{ label: "Value", value: "Value" },
{ label: "Culture", value: "Culture" },
]}
defaultValue={{ label: "Key", value: "Key" }}
getOptionLabel={(option) => `${option.label}`}
getOptionValue={(option) => `${option.value}`}
onChange={(n) => setSortPropertyName(n!.value)}
/>
</div>
</div>
<Table id="table">
<thead>
<th>Key</th>
<th>Value</th>
<th>Comment</th>
<th>Language</th>
<th></th>
</thead>
<tbody>
{resources.items.map((resx) => (
<tr>
<td id={resx.key}>{resx.key}</td>
<td id={resx.key + resx.culture + "value"}>
<div id="value" contentEditable>
{resx.value}
</div>
</td>
<td id={resx.key + resx.culture + "comment"}>
<div id="comment" contentEditable>
{resx.comment}
</div>
</td>
<td id={resx.key + resx.culture}>{resx.culture}</td>
<td>
<Button
className="myButton"
onClick={() => editString(resx)}
>
Save
</Button>
</td>
</tr>
))}
</tbody>
</Table>
<Select
className="select"
isSearchable={false}
closeMenuOnSelect={true}
id="count"
options={[
{ label: 5, value: 5 },
{ label: 10, value: 10 },
{ label: 20, value: 20 },
{ label: 50, value: 50 },
{ label: 100, value: 100 },
]}
defaultValue={{ label: 5, value: 5 }}
getOptionLabel={(option) => `${option.label}`}
getOptionValue={(option) => `${option.value}`}
onChange={(n) => setItemsPerPage(n!.value)}
/>
<div>
<Pagination>
<Pagination.First onClick={() => firstList()} />
<Pagination.Prev
onClick={() => previousList()}
id="prev"
disabled={onChangePrev()}
/>
<Pagination.Next
onClick={() => nextList()}
id="next"
disabled={onChangeNext()}
/>
<Pagination.Last onClick={() => lastList()} />
</Pagination>
</div>
</div>
</div>
);
}
}
The checkUndefined function was an attempt to clear the row.
Here are some pictures to show better my problem.
I added the "we" in the second row
And after clicking the button to see the next page of the table the "we" is still there, in that place would be a empty fields.

React update state only when button is clicked rather than updating whenever something is written in input

I've got a react app. And I was making filter section where user puts max price of article.
Now everything works, only thing that is, page is rerendering on every single input in input box, even there is an button.
What would be the way to stop rerendering of a page? I want it to rerender only if button is pressed - so I only want to remove this rerendering when user inputs a price. Eg. User want to input price 200000 but page refreshes when he types 2,0,0 etc. I want to be able to input 200000 without refreshing only if button is pressed.
Thanks!
Here is my dashboard.js
const Dashboard = () => {
const form = useRef();
const checkBtn = useRef();
const pageSearchParam = new URLSearchParams(window.location.search);
const pageParam = Number(pageSearchParam.get('page')) || 1;
const maxPriceSearchParam = new URLSearchParams(window.location.search);
const maxPriceParam = Number(maxPriceSearchParam.get('maxprice'));
const parsedUrl = new URL(window.location.href);
const filterNameInURL = parsedUrl.searchParams.get('filter');
const [content, setContent] = useState([]);
const [maxPrice, setMaxPrice] = useState(maxPriceParam || []);
// eslint-disable-next-line
const [page, setPage] = useState(pageParam);
const [total, setTotal] = useState(0);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (filterNameInURL) {
const fetchFiltered = async () => {
const res = await ArticleService.filterByName(filterNameInURL, page);
const { count, rows } = await res.data;
setTotal(count);
setContent(rows);
};
fetchFiltered();
} else if (maxPrice) {
const fetchWithMaxPrice = async () => {
const res = await ArticleService.filterByMaxPrice(maxPrice, page);
const { count, rows } = await res.data;
setTotal(count);
setContent(rows);
};
fetchWithMaxPrice();
} else {
const fetchPosts = async () => {
const res = await ArticleService.articles(page);
const { count, rows } = await res.data;
setTotal(count);
setContent(rows);
};
fetchPosts();
}
}, [filterNameInURL, page, maxPrice]);
const onChangeMaxPrice = (e) => {
const maxprice = e.target.value;
setMaxPrice(maxprice);
};
const handleFilter = async (e) => {
e.preventDefault();
form.current.validateAll();
setLoading(true);
if (checkBtn.current.context._errors.length === 0) {
try {
onsubmit = () => {
maxPriceSearchParam.set('maxprice', maxPrice);
window.location.search = maxPriceSearchParam.toString();
};
} catch (error) {
console.log(error);
}
} else {
setLoading(false);
}
};
const render = (item, index) => {
return (
<tr key={index}>
<td className='text-center'>
<div key={item.id}>
<img
src={`${item.pictures}`}
alt='picture'
className='rounded'
></img>
</div>
</td>
<td className='text-center'>
<div key={item.id}>
<h4>{item.descr}</h4>
<br></br>
<h6 className='text-left'>No of sqm: {item.sqm}m2</h6>
<div className='text-left'>
<small className='text-left'>
{' '}
<a href={item.link} target='_blank' rel='noopener noreferrer'>
Show on page
</a>
</small>
</div>
</div>
</td>
<td className='text-center'>
<div key={item.id}>
<h4>{item.price}</h4>
<small className='text-left'>Price per m2: {item.ppm2}</small>
</div>
</td>
<td className='text-center'>
<div key={item.id}>
<Link to={`/article/${item.id}`}>
<h4>Show</h4>
</Link>
</div>
</td>
</tr>
);
};
const capitalize = (str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
};
const renderHeader = () => {
if (filterNameInURL) {
return (
<h4 className='text-center'>
Total {total} articles on
{capitalize(filterNameInURL)}
</h4>
);
} else {
return (
<h4 className='text-center'>
Total {total} articles in DB
</h4>
);
}
};
return (
<div>
<div className='container'>
{renderHeader()}
<Form onSubmit={handleFilter} ref={form}>
Filters <br></br> Max price:
<input
type='text'
className='form text-center'
placeholder='npr. 120000'
aria-describedby='basic-addon2'
value={maxPrice}
onChange={onChangeMaxPrice}
/>
<button className='btn btn-primary btn-block w-25' disabled={loading}>
{loading && (
<span className='spinner-border spinner-border-sm'></span>
)}
<span>Filter</span>
</button>
<CheckButton style={{ display: 'none' }} ref={checkBtn} />
</Form>
<div className='table-responsive'>
<table className='table'>
<thead className='thead-dark'>
<tr>
<th className='text-center' scope='col'>
Picture
</th>
<th className='text-center' scope='col'>
Description
</th>
<th className='text-center w-25' scope='col'>
Price
</th>
<th className='text-center' scope='col'>
Offer
</th>
</tr>
</thead>
<tbody>{content.map(render)}</tbody>
</table>
</div>
</div>
<div className='mb-5 text-center'>
<Pagination
totalPages={Math.ceil(total / 10)}
onPageChange={(e, d) => {
pageSearchParam.set('page', d.activePage);
window.location.search = pageSearchParam.toString();
}}
activePage={page}
/>
</div>
</div>
);
};
export default Dashboard;
You are changing state on onChange function. So it forces re-render on every time when you type a letter in input box.
Take a new state and put that in useEffect instead of maxPrice. Set this state on buttonPress.
useEffect(() => {
// all code here
}, [filterNameInURL, page, newState]);
const onButtonPress () => {
setNewState(maxPrice)
}
Following document will help you to understand it in more details.
useEffect doc

Categories

Resources