React CRUD Remove Entry From Table - javascript

I'm building a CRUD app in React (similar to the todo apps on the net), however the main difference is I am appending each entry to a bootstrap Table. This might not be the best way to represent the data, but it helps me get off the ground quickly without having to go over some CSS styling, which I'm pretty weak at.
My goal is to be able to delete, after a warning prompt, any given entry from the Table. However, I am not sure of the best way to do this. So here is the Form to enter a player's name:
import React, { useState } from "react";
import { Form, Button } from "react-bootstrap";
const PlayerForm = ({ addPlayer }) => {
const [name, setName] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
addPlayer(name);
setName("");
};
return (
<Form onSubmit={handleSubmit}>
<Form.Group controlId="name">
<Form.Label>Name</Form.Label>
<Form.Control
required
type="text"
value={name}
placeholder="Normal text"
onChange={(e) => setName(e.target.value)}
/>
</Form.Group>
<Button type="submit">Add Player</Button>
</Form>
);
};
export default PlayerForm;
And after that, the data goes into a PlayerList component:
import React, { useState } from "react";
import { v4 as uuidv4 } from "uuid";
import { Table, Form } from "react-bootstrap";
import PlayerForm from "./PlayerForm";
import styled from "styled-components";
const StyledInput = styled(Form.Control)`
padding: 2px 5px;
width: 60px;
height: 30px;
`;
const PlayerList = () => {
const [players, setPlayers] = useState([
{ name: "Harry Kane", country: "England", id: 1, goals: 0, percentage: 0 },
{
name: "Marcus Rashford",
country: "England",
id: 2,
goals: 0,
percentage: 0,
},
]);
const addPlayer = (name) => {
setPlayers([
...players,
{ name: name, id: uuidv4(), country: "England", goals: 0, percentage: 0 },
]);
};
return (
<div>
<Table>
<thead>
<tr>
<th>Name</th>
<th>Total Goals</th>
<th>Goal Percentage</th>
</tr>
</thead>
<tbody>
{players.map((player) => (
<tr key={player.id}>
<td>{player.name}</td>
<td>
<Form>
<Form.Group controlId="goals">
<StyledInput
size="sm"
required
type="number"
defaultValue={player.goals}
step={1}
className="smaller-input"
min="0"
/>
</Form.Group>
</Form>
</td>
<td>
<Form>
<Form.Group controlId="goals">
<StyledInput
size="sm"
required
type="number"
defaultValue={player.percentage}
step={1}
className="smaller-input"
min="0"
/>
</Form.Group>
</Form>
</td>
</tr>
))}
</tbody>
</Table>
<PlayerForm addPlayer={addPlayer} />
</div>
);
};
export default PlayerList;
Now I would like to be able to delete any given player after adding them to the Table. I'm not sure how to proceed beyond building a function
const removePlayer =() =>{
}
Please could someone help me with this?

first, you have to send the player id to the function then filter out that player
const removePlayer = (playerId) => {
setPlayer(player.filter(p => p.id !== playerId));
}

Related

Redux with redux toolkit: UI is not changing

I'm new to redux and redux toolkit in React.js. Trying my best to make my PET project to apply for a future job, but faced a problem. I'll try to describe it.
Firstly, the code. removeInvoice function in invoice-slice.js file:
import { createSlice } from "#reduxjs/toolkit";
import { INVOICES_LIST } from "../Pages/Invoice/InvoicesList";
const invoiceSlice = createSlice({
name: "invoice",
initialState: {
invoices: INVOICES_LIST,
},
reducers: {
addNewInvoice(state, action) {
const newItem = action.payload;
state.invoices.push({
id: newItem.id,
billFrom: newItem.bill_from,
billFromAddress: newItem.billFromAddress,
billTo: newItem.bill_to,
billToAddress: newItem.bill_to_address,
invoiceNumber: newItem.invoice_num,
});
console.log(newItem);
},
removeInvoice(state, action) {
const id = action.payload;
state.invoices = state.invoices.filter((item) => item.id !== id);
console.log(action);
console.log(state.invoices);
},
editInvoice() {},
},
});
export const invoiceActions = invoiceSlice.actions;
export default invoiceSlice;
INVOICES_LIST looks like this:
export const INVOICES_LIST = [
{
id: Math.random().toString(),
number: Math.random().toFixed(2),
invoice_num: "#1232",
bill_from: "Pineapple Inc.",
bill_to: "REDQ Inc.",
total_cost: "14630",
status: "Pending",
order_date: "February 17th 2018",
bill_from_email: "pineapple#company.com",
bill_from_address: "86781 547th Ave, Osmond, NE, 68765",
bill_from_phone: "+(402) 748-3970",
bill_from_fax: "",
bill_to_email: "redq#company.com",
bill_to_address: "405 Mulberry Rd, Mc Grady, NC, 28649",
bill_to_phone: "+(740) 927-9284",
bill_to_fax: "+0(863) 228-7064",
ITEMS: {
item_name: "A box of happiness",
unit_costs: "200",
unit: "14",
price: "2800",
sub_total: "133300",
vat: "13300",
grand_total: "14630",
},
},
{
id: Math.random().toString(),
number: Math.random().toFixed(2),
invoice_num: "#1232",
bill_from: "AMD Inc.",
bill_to: "Intel Inc.",
total_cost: "14630",
status: "Delivered",
order_date: "February 17th 2018",
bill_from_email: "pineapple#company.com",
bill_from_address: "86781 547th Ave, Osmond, NE, 68765",
bill_from_phone: "+(402) 748-3970",
bill_from_fax: "",
bill_to_email: "redq#company.com",
bill_to_address: "405 Mulberry Rd, Mc Grady, NC, 28649",
bill_to_phone: "+(740) 927-9284",
bill_to_fax: "+0(863) 228-7064",
ITEMS: {
item_name: "Unicorn Tears",
unit_costs: "500",
unit: "14",
price: "1700",
sub_total: "133300",
vat: "13300",
grand_total: "14630",
},
},
{
id: Math.random().toString(),
number: Math.random().toFixed(2),
invoice_num: "#1232",
bill_from: "Apple Inc.",
bill_to: "Samsung",
total_cost: "14630",
status: "Shipped",
order_date: "February 17th 2018",
bill_from_email: "pineapple#company.com",
bill_from_address: "86781 547th Ave, Osmond, NE, 68765",
bill_from_phone: "+(402) 748-3970",
bill_from_fax: "",
bill_to_email: "redq#company.com",
bill_to_address: "405 Mulberry Rd, Mc Grady, NC, 28649",
bill_to_phone: "+(740) 927-9284",
bill_to_fax: "+0(863) 228-7064",
ITEMS: {
item_name: "Rainbow Machine",
unit_costs: "700",
unit: "5",
price: "3500",
sub_total: "133300",
vat: "13300",
grand_total: "14630",
},
},
];
AllInvoices.js file where i map invoices:
import React, { Fragment } from "react";
import { useDispatch, useSelector } from "react-redux";
import { uiActions } from "../../store/ui-slice";
// import { invoiceActions } from "../../store/invoice-slice";
import { INVOICES_LIST } from "../Invoice/InvoicesList";
import Wrapper from "../../UI/Wrapper";
import Card from "../../UI/Card";
import Footer from "../../UI/Footer";
import Button from "../../UI/Button";
// import InvoiceItemDescription from "./InvoiceItemDescription";
// import EditInvoiceItem from "./EditInvoiceItem";
import classes from "./AllInvoices.module.css";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faChevronDown } from "#fortawesome/free-solid-svg-icons";
// import AddInvoiceItem from "./AddInvoiceItem";
import { Link } from "react-router-dom";
import Invoice from "./Invoice";
const AllInvoices = (props) => {
// const { id } = props;
const dispatch = useDispatch();
const toggleSelectOptions = () => {
dispatch(uiActions.toggleSelectOptions());
};
// const removeInvoiceItem = (id) => {
// dispatch(invoiceActions.removeInvoice(id));
// };
const showMoreOptions = useSelector(
(state) => state.ui.selectOptionsIsVisible
);
// const invoice = useSelector((state) => state.invoices);
return (
<Fragment>
<Wrapper isShrinked={props.isShrinked}>
<Card>
<h1 className={classes.header}>Invoice</h1>
<div className={classes.content}>
<div className={classes["btn-wrapper"]}>
<Link to="/invoices/add-invoice">
<Button>Add Invoice</Button>
</Link>
</div>
<div className={classes.invoices}>
{showMoreOptions && (
<ul className={classes.list}>
<li>Select all invoices</li>
<li>Unselect all</li>
<li>Delete selected</li>
</ul>
)}
<table>
<colgroup>
<col className={classes.col1}></col>
<col className={classes.col2}></col>
<col className={classes.col3}></col>
<col className={classes.col4}></col>
<col className={classes.col5}></col>
<col className={classes.col6}></col>
<col className={classes.col7}></col>
</colgroup>
<thead className={classes["table-head"]}>
<tr>
<th className={classes.position}>
<span className={classes.checkbox}>
<input type="checkbox"></input>
</span>
<FontAwesomeIcon
icon={faChevronDown}
className={classes.chevron}
onClick={toggleSelectOptions}
/>
</th>
<th>
<span className={classes["thead-text"]}>Number</span>
</th>
<th>
<span className={classes["thead-text"]}>Bill From</span>
</th>
<th>
<span className={classes["thead-text"]}>Bill To</span>
</th>
<th>
<span className={classes["thead-text"]}>Total Cost</span>
</th>
<th>
<span className={classes["thead-text"]}>Status</span>
</th>
</tr>
</thead>
<tbody>
{INVOICES_LIST.map((invoice, index) => (
<Invoice
key={index}
invoiceItem={{
id: invoice.id,
invoice_num: invoice.invoice_num,
bill_from: invoice.bill_from,
bill_to: invoice.bill_to,
status: invoice.status,
}}
/>
))}
</tbody>
</table>
</div>
</div>
</Card>
<Footer />
</Wrapper>
</Fragment>
);
};
export default AllInvoices;
And Invoice.js file where i should use removeInvoice:
import React from "react";
import classes from "./Invoice.module.css";
import { useDispatch } from "react-redux";
import { Link } from "react-router-dom";
import { invoiceActions } from "../../store/invoice-slice";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faTrash } from "#fortawesome/free-solid-svg-icons";
const Invoice = (props) => {
const { id, invoice_num, bill_from, bill_to, status } = props.invoiceItem;
const dispatch = useDispatch();
const removeInvoiceItem = () => {
dispatch(invoiceActions.removeInvoice(id));
};
return (
<tr className={classes.height}>
<td>
<span className={classes.checkbox}>
<input type="checkbox"></input>
</span>
</td>
<td>
<span>{invoice_num}</span>
</td>
<td>
<span>{bill_from}</span>
</td>
<td>
<span>{bill_to}</span>
</td>
<td>
<span>14300</span>
{/* This should be a dynamic value later */}
</td>
<td>
<span
className={`${
status === "Pending" ? classes["status-pending"] : ""
} ${status === "Delivered" ? classes["status-delivered"] : ""} ${
status === "Shipped" ? classes["status-shipped"] : ""
}`}
>
{status}
</span>
</td>
<td>
<div className={classes.buttons}>
<Link to={`/invoices/invoice-description/${id}`}>
<button className={classes["view-btn"]}>View</button>
</Link>
<button className={classes["delete-btn"]} onClick={removeInvoiceItem}>
<FontAwesomeIcon icon={faTrash} />
</button>
</div>
</td>
</tr>
);
};
export default Invoice;
Now, the issue. It seems to remove the invoice from an array, because array changes from 3 items to 2, and shows in a console payload with appropriate id of item which i wanted to remove by clicking on a button, but UI console.log here doesn't reflect the changes, there is still 3 invoice items instead of 2 or less. Anyone know what can be the problem?
I've already tried alot of variants, like to pass an id to a function like this:
const removeInvoiceItem = (id) => {
dispatch(invoiceActions.removeInvoice(id));
};
Tried to make it with curly braces:
const removeInvoiceItem = (id) => {
dispatch(invoiceActions.removeInvoice({ id }));
};
Also tried anonymous function here:
<button className={classes["delete-btn"]} onClick={() => removeInvoiceItem(id)}>
<FontAwesomeIcon icon={faTrash} />
</button>
And so on. I know that if UI doesn't change, then state is not changing, but, in my case, i overwrite the state like this:
state.invoices = state.invoices.filter((item) => item.id !== id);
So, i don't know what else to do. Thought of useSelector and tried it like this:
const invoice = useSelector((state) => state.invoices);
And in map function:
{invoice.map((invoice, index) => (
<Invoice
key={index}
invoiceItem={{
id: invoice.id,
invoice_num: invoice.invoice_num,
bill_from: invoice.bill_from,
bill_to: invoice.bill_to,
status: invoice.status,
}}
/>
))}
But it was crashing the page and telling me this error: Uncaught TypeError: invoice.map is not a function.
So, i don't know what to do else. Please, help me!!!
P.s. I'm new in stackoveflow, so sorry if something wrong :)
The problem is that you're using the constant INVOICE_LIST to map your elements instead of the current state of the store.
You used INVOICE_LIST to initialize your slice, that's good. But then you did not use what you initialized, you simply used the constant, and that's why the UI remained constant.
You should use useSelector to access that state like so:
const invoiceList = useSelector(state => state.invoice.invoices)
This should be the correct syntaxe in your case:
state.sliceName.wantedProperty
Now when you map on "invoiceList" instead of "INVOICE_LIST", this should do the trick!
You aren't rerendering the INVOICE_LIST when it changes. You would want to have a useEffect or something similar that will rerender the component when the INVOICE_LIST changes to see any changes on the UI side.
Your problem is this:
{INVOICES_LIST.map((invoice, index) => (
<Invoice
key={index}
invoiceItem={{
id: invoice.id,
invoice_num: invoice.invoice_num,
bill_from: invoice.bill_from,
bill_to: invoice.bill_to,
status: invoice.status,
}}
/>
))}
This is rendering static content and will not change even when you make a change to the redux store. You need to change this to state that will rerender when it changes.

Uncontrolled input React Hooks ( console error)

Warning: A component is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.
import React, { useEffect, useState } from 'react';
import axios from "axios"
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
function CreateExercise() {
const [createExercises, setExercise] = useState({
username: "",
description: "",
duration: 0,
date: new Date(),
users: []
});
useEffect(() => {
axios.get('http://localhost:5000/users/')
.then(response => {
if (response.data.length > 0) {
setExercise({
users: response.data.map(user => user.username),
username: response.data[0].username
})
}
})
}, [])
function handleChange(event) {
const { name, value } = event.target;
setExercise(prevExercise => {
return {
...prevExercise,
[name]: value
};
});
}
function changeDate(date) {
setExercise(prevExercise => {
return {
username: prevExercise.username,
description: prevExercise.description,
duration: prevExercise.duration,
date: date,
users: prevExercise.users
};
});
}
function onSubmit(event) {
event.preventDefault();
console.log(createExercises);
axios.post('http://localhost:5000/exercises/add', createExercises)
.then(res => console.log(res.data));
setExercise({
username: "",
description: "",
duration: 0,
date: new Date(),
users: []
});
window.location = '/';
}
return (
<div>
<h3>Create New Exercise log</h3>
<form >
<div>
<label>Username: </label>
<select
required
className="form-control"
value={createExercises.username}
onChange={handleChange}>
{
createExercises.users.map(function (user, index) {
return <option key={user} value={user}>{user}</option>;
})
}
</select>
</div>
<div className="form-group">
<label>Description: </label>
<input type="text"
name="description"
className="form-control"
onChange={handleChange}
value={createExercises.description}
/>
</div>
<div className="form-group">
<label>Duration (in minutes): </label>
<input type="text"
name="duration"
className="form-control"
onChange={handleChange}
value={createExercises.duration}
/>
</div>
<div className="form-group">
<label>Date: </label>
<DatePicker
selected={createExercises.date}
onChange={changeDate}
/>
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary" onClick={onSubmit} >Create Exercise Log</button>
</div>
</form>
</div>
);
}
export default CreateExercise;
how can i avoid above console error occured?
I think your problem is in your effect, particularly in the way you use setExercise, when you do:
setExercise({
users: response.data.map(user => user.username),
username: response.data[0].username
})
It doesn't "merge" (assign) the new data with previous state, what it does - is just sets the state, meaning your state object after this will be:
{ users:[], username:''}
So you actually lose description and other fields - hence the warning.
What you should do, is this:
setExercise((prevState) => ({
...prevState,
users: response.data.map(user => user.username),
username: response.data[0].username
}))

React. Transferring data from textarea to array JSON

I just started working with React and JSON and require some help. There is a textarea field in which a user enters some data. How to read row-wise the entered text as an array into a JSON variable of the request? Any assistance would be greatly appreciated.
The result I want is
{
id: 3,
name: 'Monika',
birthDay: '1999/01/01',
countryDTO: 'USA',
films: [
'Leon:The Professional',
'Star wars',
'Django Unchained',
],
} ```
My code:
import React from 'react';
import { Form, FormGroup, Label } from 'reactstrap';
import '../app.css';
export class EditActor extends React.Component {
state = {
id: '',
name: '',
birthDay: '',
countryDTO: '',
films: [],
}
componentDidMount() {
if (this.props.actor) {
const { name, birthDay, countryDTO, films } = this.props.actor
this.setState({ name, birthDay, countryDTO, films });
}
}
submitNew = e => {
alert("Actor added"),
e.preventDefault();
fetch('api/Actors', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: this.state.name,
birthDay: this.state.birthDay,
countryDTO: {
title: this.state.countryDTO
},
films: [{ title: this.state.films }]
})
})
.then(() => {
this.props.toggle();
})
.catch(err => console.log(err));
this.setState({
id: '',
name: '',
birthDay: '',
countryDTO: '',
films: ''
});
}
onChange = e => {
this.setState({ [e.target.name]: e.target.value })
}
render() {
return <div>
<table>
<tr>
<td colspan="2">
<h3> <b>Add actor</b></h3>
<FormGroup>
<Label for="id">Id: </Label>
<input type="text" name="id" onChange={this.onChange} value={this.state.id} /><p />
<Label for="name">Name:</Label>
<input type="text" name="name" onChange={this.onChange} value={this.state.name} /><p />
<Label for="birthDay">Birth day:</Label>
<input type="text" name="birthDay" onChange={this.onChange} value={this.state.birthDay} placeholder="1990/12/31" /><p />
<Label for="country">Country:</Label>
<input type="text" name="countryDTO" onChange={this.onChange} value={this.state.countryDTO} /><p />
<Label for="Films">Films:</Label>
<textarea name="films" value={this.state.films} onChange={this.onChange} /><p />
</FormGroup>
</td>
</tr>
<tr>
<td>
<Form onSubmit={this.submitNew}>
<button class="editButtn">Enter</button>
</Form>
</td>
</tr>
</table >
</div>;
}
}
export default EditActor;
If you change the below code it will work automatically.
State declaration
this.state = {
name: 'React',
films:["Palash","Kanti"]
};
Change in onechange function
onChange = e => {
console.log("values: ", e.target.value)
this.setState({ [e.target.name]: e.target.value.split(",") })
}
change in textarea
<textarea name="films" value={this.state.films.map(r=>r).join(",")} onChange={this.onChange} />
Code is here:
https://stackblitz.com/edit/react-3hrkme
You have to close textarea tag and the following code is :
<textarea name="films" value={this.state.films} onChange={this.onChange} >{this.state.films}</textarea>
My understanding of your problem is that you would like to have each line in the text area dynamically added as an entry in the films array. This can be achieved as follows:
import React, { Component } from "react";
export default class textAreaRowsInState extends Component {
constructor(props) {
super(props);
this.state = {
currentTextareaValue: "",
films: []
};
}
handleChange = e => {
const { films } = this.state;
const text = e.target.value;
if (e.key === "Enter") {
// Get last line of textarea and push into films array
const lastEl = text.split("\n").slice(-1)[0];
films.push(lastEl);
this.setState({ films });
} else {
this.setState({ currentTextareaValue: text });
}
};
render() {
const { currentTextareaValue } = this.state;
return (
<textarea
defaultValue={currentTextareaValue}
onKeyPress={this.handleChange}
/>
);
}
}
Keep in mind that this method is not perfect. For example, it will fail if you add a new line anywhere other than at the end of the textarea. You can view this solution in action here:
https://codesandbox.io/s/infallible-cdn-135du?fontsize=14&hidenavigation=1&theme=dark
change textarea() tag
to
<textarea name="films" value={this.state.films} onChange={this.onChange} >{this.state.films}</textarea>
You can use split() :
films: {this.state.films.split(",")}

How to only delete one item at a time in ReactJS?

I'd like to, when a user deletes on row, for only that row to be deleted. Currently that only happens sometimes. And when you have only two items left to delete, when you click on the delete button, the row's data toggles and replaces itself. It doesn't actually delete.
mainCrud.js - houses the add and delete
crudAdd.js - defines state, event handlers, renders the form itself
crudTable.js - maps pre-defined rows defined in mainCrud.js, renders the table itself
Link to CodeSandbox (tables are under campaigns, dev and news tabs).
Any idea what could be causing this?
MainCrud.js
import React, { useState } from "react";
import CrudIntro from "../crud/crudIntro/crudIntro";
import CrudAdd from "../crud/crudAdd/crudAdd";
import CrudTable from "../crud/crudTable/crudTable";
const MainCrud = props => {
// Project Data
const projectData = [
{
id: 1,
name: "Skid Steer Loaders",
description:
"To advertise the skid steer loaders at 0% financing for 60 months.",
date: "February 1, 2022"
},
{
id: 2,
name: "Work Gloves",
description: "To advertise the work gloves at $15.",
date: "February 15, 2022"
},
{
id: 3,
name: "Telehandlers",
description: "To advertise telehandlers at 0% financing for 24 months.",
date: "March 15, 2022"
}
];
const [projects, setProject] = useState(projectData);
// Add Project
const addProject = project => {
project.id = projectData.length + 1;
setProject([...projects, project]);
};
// Delete Project
const deleteProject = id => {
setProject(projectData.filter(project => project.id !== id));
};
return (
<div>
<section id="add">
<CrudIntro title={props.title} subTitle={props.subTitle} />
<CrudAdd addProject={addProject} />
</section>
<section id="main">
<CrudTable projectData={projects} deleteProject={deleteProject} />
</section>
</div>
);
};
export default MainCrud;
CrudAdd.js
import React, { Component } from "react";
import "../crudAdd/crud-add.scss";
import "../../button.scss";
class CrudAdd extends Component {
state = {
id: null,
name: "",
description: "",
date: ""
};
handleInputChange = e => {
let input = e.target;
let name = e.target.name;
let value = input.value;
this.setState({
[name]: value
});
};
handleFormSubmit = e => {
e.preventDefault();
this.props.addProject({
id: this.state.id,
name: this.state.name,
description: this.state.description,
date: this.state.date
});
this.setState({
// Clear values
name: "",
description: "",
date: ""
});
};
render() {
return (
<div>
<form onSubmit={this.handleFormSubmit}>
<input
name="name"
type="name"
placeholder="Name..."
id="name"
value={this.state.name}
onChange={e => this.setState({ name: e.target.value })}
required
/>
<input
name="description"
type="description"
placeholder="Description..."
id="description"
value={this.state.description}
onChange={e => this.setState({ description: e.target.value })}
required
/>
<input
name="date"
type="name"
placeholder="Date..."
id="date"
value={this.state.date}
onChange={e => this.setState({ date: e.target.value })}
required
/>
<button type="submit" className="btn btn-primary">
Add Project
</button>
</form>
</div>
);
}
}
export default CrudAdd;
CrudTable.js
import React, { Component } from "react";
import "../crudTable/crud-table.scss";
class CrudTable extends Component {
render() {
const props = this.props;
return (
<div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th scope="col">Project Name</th>
<th scope="col">Project Description</th>
<th scope="col">Date</th>
<th scope="col"> </th>
</tr>
</thead>
<tbody>
{props.projectData.length > 0 ? (
props.projectData.map(project => (
<tr key={project.id}>
<td>{project.name}</td>
<td>{project.description}</td>
<td>{project.date}</td>
<td>
<button className="btn btn-warning">Edit</button>
<button
onClick={() => props.deleteProject(project.id)}
className="btn btn-danger"
>
Delete
</button>
</td>
</tr>
))
) : (
<tr>
<td>No projects found. Please add a project.</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
);
}
}
export default CrudTable;
This is because you are filtering over projectData. Update your deleteProject method to filter over your React.useState projects variable and it will work.
const deleteProject = id => {
setProject(projects.filter(project => project.id !== id));
};
See code sandbox example here.

I am getting Unhandled Rejection (TypeError): Cannot read property 'temp' of undefined when trying to build a react app using openweatherapi

I am trying to build a weather app usind the open weather api https://openweathermap.org/guide and i am getting this error when clicking the get weather button.
This is my main app.js renamed to Profile.js
import React, { Component } from 'react'
import jwt_decode from 'jwt-decode'
import Heading from './heading'
import Form from './form'
import Forecast from './forcast';
const api_key="secretnumber";
class Profile extends React.Component {
componentDidMount() {
const token = localStorage.usertoken
const decoded = jwt_decode(token)
this.setState({
first_name: decoded.first_name,
last_name: decoded.last_name,
email: decoded.email
})
}
state={
temperature : "",
city : "",
country:"",
humidity:"",
pressure:"",
icon:"",
description:"",
error:""
}
getWeather = async (e) => {
const city = e.target.elements.city.value;
const country = e.target.elements.country.value;
e.preventDefault();
const api_call = await fetch('http://api.openweathermap.org/data/2.5/weather?q=${city},${country}&units=metric&appid=${api_key}');
const response = await api_call.json();
if(city && country){
this.setstate({
temperature: response.main.temp,
city: response.name,
country: response.sys.country,
humidity: response.main.humidity,
pressure: response.weather[0].icon,
description:response.weather[0].description,
error:""
})
}else{
this.setState({
error: "Please fill out input fields..."
})
}
}
render() {
return (
<div className="container">
<div className="jumbotron mt-5">
<div className="col-sm-8 mx-auto">
<h1 className="text-center">PROFILE</h1>
</div>
<table className="table col-md-6 mx-auto">
<tbody>
<tr>
<td>Fist Name</td>
<td>{this.state.first_name}</td>
</tr>
<tr>
<td>Last Name</td>
<td>{this.state.last_name}</td>
</tr>
<tr>
<td>Email</td>
<td>{this.state.email}</td>
</tr>
</tbody>
</table>
<div>
<Heading/>
<Form loadWeather={this.getWeather}/>
<Forecast
temperature={this.state.temperature}
city={this.state.city}
country={this.state.country}
humidity={this.state.humidity}
pressure={this.state.pressure}
icon={this.state.icon}
description={this.state.description}
error={this.state.error}/>
</div>
</div>
</div>
)
}
}
export default Profile
This is forcast.js
import React from 'react';
const Forecast = (props) =>{
return(
<div>
{props.country && props.city && <p>Location:{props.city},{props.country}</p>}
{props.temperature && <p>Temperature: {props.temperature}</p>}
{props.humidity && <p>Humidity:{props.humidity}</p>}
{props.pressure && <p>Pressure: {props.pressure}</p>}
{props.icon && <img src="" alt="weather icon"/>}
{props.description && <p>Conditions:{props.description}</p>}
{props.error && <p>{props.error}</p>}
</div>
)
}
export default Forecast;
And this is my form.js
import React from 'react';
const Form = (props) =>{
return(
<form onSubmit = {props.loadWeather}>
<input type="text" name="city" placeholder="Choose a City" value="London"/>
<input type="text" name="country" placeholder="Choose a Country" value="uk"/>
<button>Get Weather</button>
</form>
)
}
export default Form;
I am trying with city London and country uk and I am getting the error mentioned above.
Thank you for your help. Really appreciate if this problem can be solved.

Categories