React.js POST method issue - javascript

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;

Related

React Redux, "return" is not working in a specific Redux Action function when returning a function

I'm trying to update a customer's name using React-Redux. This is my component code:
import React, { useEffect, useState } from "react";
import { Link, Navigate, useParams } from 'react-router-dom';
import { connect } from 'react-redux';
import { customerDetail, deleteCustomer, updateCustomer } from "../../redux";
const CustomerDetail = ( {customerDetail, userData} ) => {
let actionType = ''
const { cid } = useParams()
useEffect(() => {
customerDetail(cid)
}, [])
const [formData, setFormData] = useState({
customer_name: ''
});
const { customer_name } = formData;
const onChange = e => setFormData({ ...formData, [e.target.name]: e.target.value });
const onClick = e => {
actionType = e.target.name;
}
const onSubmit = e=> {
e.preventDefault();
console.log('submit clicked')
actionType === 'update' ? updateCustomer(cid, customer_name) : deleteCustomer();
};
return userData ? (
<div>
<form onSubmit={e => onSubmit(e)}>
<table className="table">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Customer Name</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
<tr>
<td>{userData.id}</td>
<td>
<input
placeholder={userData.customer_name}
className='form-control'
id="exampleInputCustomerName"
name="customer_name"
value={customer_name}
onChange={e => onChange(e)}
>
</input>
</td>
<td>
<button
type="submit"
name="update"
className="btn btn-primary"
onClick={e => onClick(e)}
>Update
</button>
<button
type="submit"
name="delete"
className="btn btn-danger"
onClick={e => onClick(e)}
>Delete
</button>
</td>
</tr>
</tbody>
</table>
</form>
</div>
) : (
<div>
Please login first
</div>
)
};
const mapStateToProps = state => ({
// is authenticated?
isAuthenticated: state.auth.isAuthenticated,
userData: state.customer.customer
})
const mapDispatchToProps = dispatch => {
return {
customerDetail: cid => dispatch(customerDetail(cid)),
updateCustomer: (customer_name, cid) => dispatch(updateCustomer(cid, customer_name)),
deleteCustomer: () => dispatch(deleteCustomer())
}
}
export default connect(mapStateToProps, mapDispatchToProps) (CustomerDetail);
The function that has problem is updateCustomer function
This is the code snippet of updateCustomer function:
export const updateCustomer = (cid, customer_name) => {
console.log("Update action called")
console.log(cid)
console.log(customer_name)
return (dispatch) => {
console.log('dispatch called')
const config = {
headers: {
'Content-Type': 'application/json',
'Authorization': `JWT ${localStorage.getItem('access')}`,
'Accept': 'application/json'
}
}
const body = JSON.stringify({ customer_name });
console.log(body)
dispatch(updateCustomersRequest)
axios.put(`${process.env.REACT_APP_API_URL}/api/users/${cid}/`, body, config)
.then(response => {
const users = response.data
console.log(response)
dispatch(updateCustomersSuccess(users))
})
.catch(error => {
const errorMsg = error.message
dispatch(updateCustomersFailure(errorMsg))
})
}
}
I can view cid, customer_name, and "Update action called" in my terminal, but I can't view "dispatch called" in my terminal.
My other action functions work well, this makes me feel really confused.
If I change the return function to only return console.log(), I can view it then. I feel like I just can't return a function in this action.
I got it. I forgot to add my action in the header of this component. But I really don't know the error would be like this. This is a good lesson for me...

How to display different tables on click in React?

I am making a simple todo. I am fetching data from an API and I want to show all the items in a table by default. There will be 3 buttons - All, Complete and Incomplete which will show All, Completed and Incompleted todos table respectively. I have set states for completed and incompleted todos but can't wrap my head around how to perform conditional rendering and display different tables on different button clicks.
Below is my code -
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./style.css";
export default function App() {
const URL = 'https://jsonplaceholder.typicode.com/todos';
const [todo, setTodo] = useState([]);
const [completed, setCompleted] = useState([]);
const [incomplete, setIncomplete] = useState([]);
useEffect(()=>{
axios.get(URL)
.then(res=>setTodo(res.data));
},[])
const showCompleted = () =>{
const completeTask = todo.filter((items)=>items.completed===true);
setCompleted(completeTask);
}
const showIncomplete = () =>{
const incompleteTask = todo.filter((items)=>items.completed===false);
setIncomplete(incompleteTask);
}
return (
<div>
<h1>ToDos!</h1>
<button type="button">All</button>
<button type="button" onClick={showCompleted}>Completed</button>
<button type="button" onClick={showIncomplete}>Incomplete</button>
<hr />
<table>
<tr>
<th>ID</th>
<th>Title</th>
<th>Completed</th>
</tr>
{todo.map((items)=>
<tr key={items.id}>
<td>{items.id}</td>
<td>{items.title}</td>
<td><input type="checkbox" defaultChecked={items.completed ? true : false} /></td>
</tr>
)}
</table>
</div>
);
}
Instead of maintaining a separate state for each type have one type state that the buttons update when they're clicked. Add data attributes to the buttons to indicate what type they are and which can be picked up in the click handler.
Instead of mapping over the whole set of todos, call a function that filters out the set of data from the todo state that you need.
const { useEffect, useState } = React;
const URL = 'https://jsonplaceholder.typicode.com/todos';
function Example() {
const [todos, setTodos] = useState([]);
const [type, setType] = useState('all');
useEffect(()=>{
fetch(URL)
.then(res => res.json())
.then(data => setTodos(data));
}, []);
// Filter the todos depending on type
function filterTodos(type) {
switch(type) {
case 'completed': {
return todos.filter(todo => todo.completed);
}
case 'incomplete': {
return todos.filter(todo => !todo.completed);
}
default: return todos;
}
}
// Set the type when the buttons are clicked
function handleClick(e) {
const { type } = e.target.dataset;
setType(type);
}
// Call the filter function to get the
// subset of todos that you need based
// on the type
return (
<div>
<h1>ToDos!</h1>
<button
type="button"
className={type === 'all' && 'active'}
data-type="all"
onClick={handleClick}
>All
</button>
<button
type="button"
className={type === 'completed' && 'active'}
data-type="completed"
onClick={handleClick}
>Completed
</button>
<button
type="button"
className={type === 'incomplete' && 'active'}
data-type="incomplete"
onClick={handleClick}
>Incomplete
</button>
<hr />
<table>
<tr>
<th>ID</th>
<th>Title</th>
<th>Completed</th>
</tr>
{filterTodos(type).map(todo => {
const { id, title, completed } = todo;
return (
<tr key={id}>
<td>{id}</td>
<td>{title}</td>
<td>
<input
type="checkbox"
defaultChecked={completed ? true : false}
/>
</td>
</tr>
);
})}
</table>
</div>
);
}
ReactDOM.render(
<Example />,
document.getElementById('react')
);
button { margin-right: 0.25em; }
button:hover { cursor:pointer; }
.active { background-color: lightgreen; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Keep two states, one to store the initial data and another one to keep track of actually displayed data.
Try like this:
function App() {
const URL = "https://jsonplaceholder.typicode.com/todos";
const [todo, setTodo] = React.useState([]);
const [view, setView] = React.useState([]);
React.useEffect(() => {
fetch(URL)
.then((res) => res.json())
.then((result) => {
setTodo(result);
setView(result);
});
}, []);
const showAll = () => {
setView(todo);
};
const showCompleted = () => {
const completeTask = todo.filter((items) => items.completed === true);
setView(completeTask);
};
const showIncomplete = () => {
const incompleteTask = todo.filter((items) => items.completed === false);
setView(incompleteTask);
};
return (
<div>
<h1>ToDos!</h1>
<button type="button" onClick={showAll}>
All
</button>
<button type="button" onClick={showCompleted}>
Completed
</button>
<button type="button" onClick={showIncomplete}>
Incomplete
</button>
<hr />
<table>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Completed</th>
</tr>
</thead>
<tbody>
{view.map((items) => (
<tr key={items.id}>
<td>{items.id}</td>
<td>{items.title}</td>
<td>
<input
type="checkbox"
defaultChecked={items.completed ? true : false}
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
You can use useMemo to prepare the data to display based on some conditions/filters/search/ordering/ anything else.
So few steps to achieve that:
Optional, declare some object outside of the component to hold some constants. Maybe I choosed a poor name for that but the idea itself should be ok. FILTER_COMPLETED in the code.
Add a useState variable to hold active filter for this specific area. const [filterCompleteMode, setFilterCompleteMode] = useState(...) in the code.
Add a useMemo variable that will prepare the data to display. You can apply some ordering or additinal filtering here. todosToDisplay in the code.
Modify your JSX a bit, change <button>s and todo to todosToDisplay.
const { useState, useMemo, useEffect } = React;
const FILTER_COMPLETED = {
All: "ALL",
Complete: "COMPLETE",
Incomplete: "INCOMPLETE"
};
function App() {
const URL = "https://jsonplaceholder.typicode.com/todos";
const [todos, setTodos] = useState([]);
const [filterCompleteMode, setFilterCompleteMode] = useState(
FILTER_COMPLETED.All
);
const todosToDisplay = useMemo(() => {
if (!todos) return [];
switch (filterCompleteMode) {
case FILTER_COMPLETED.All:
return todos;
case FILTER_COMPLETED.Incomplete:
return todos.filter((x) => x.completed === false);
case FILTER_COMPLETED.Complete:
return todos.filter((x) => x.completed === true);
default:
return todos;
}
}, [todos, filterCompleteMode]);
useEffect(() => {
fetch(URL)
.then((res) => res.json())
.then((data) => setTodos(data));
}, []);
const onCompleteFilterClick = (e) => {
setFilterCompleteMode(e.target.dataset.mode);
};
return (
<div>
<h1>ToDos!</h1>
<button
type="button"
data-mode={FILTER_COMPLETED.All}
onClick={onCompleteFilterClick}
>
All
</button>
<button
type="button"
data-mode={FILTER_COMPLETED.Complete}
onClick={onCompleteFilterClick}
>
Completed
</button>
<button
type="button"
data-mode={FILTER_COMPLETED.Incomplete}
onClick={onCompleteFilterClick}
>
Incomplete
</button>
<hr />
<table>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Completed</th>
</tr>
</thead>
<tbody>
{todosToDisplay.map((item) => (
<tr key={item.id}>
<td>{item.id}</td>
<td>{item.title}</td>
<td>
<input
type="checkbox"
defaultChecked={item.completed ? true : false}
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
<div id="root"></div>
Create state:
const [whatShow, setWhatShow] = useState('All').
When you click on button change this state
next:
{todo.map((items)=>
{items.completed === whatShow && <tr key={items.id}>
<td>{items.id}</td>
<td>{items.title}</td>
<td><input type="checkbox" defaultChecked={items.completed ? true : false} /></td>
</tr>}
)}
something like this

how to delete a row in table in reactjs

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)
}

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!

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;

Categories

Resources