React Express MySQL CRUD operations Question? - mysql

I'm developing a basic to do list application utilizing Reactjs, Express, and a MySQL backend database. The application should create, read, update, and delete tasks. I have some questions regarding the update and delete operations. I want to be able to delete and update a task. I have not been able to figure out how to delete a so-called task. So far, I drafted DB's API plus routing for the delete operation within the server.js file and a click event logic within Overview.js component. But, I somehow cannot reference an id or a TASK_ID (AKA the PK) to send in the HTTP request. Refer to the onTaskDelete click event with the fetch API within Overview.js. Keep receiving "400 or Bad response from server" error. I believe, this is where the problem lies. How would I go about getting a delete task to work properly? Any help will be much appreciated! Thanks!
/* App.js */
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import './App.css';
import Scheduler from './Scheduler.js';
import Create from './Create.js';
import Modify from './Modify.js';
import Overview from './Overview.js';
import About from './About.js';
import NotFound from './NotFound.js';
import InternalServer from './InternalServer.js';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {tasks: [] };
}
componentDidMount() {
fetch('/tasks/get')
.then(response => response.json())
.then(response => this.setState({ tasks: response.data }))
.catch(error => console.error(error))
}
render() {
const { tasks } = this.state;
return (
<div className="App">
<Switch>
<Route exact path='/' render={() => (
<Scheduler tasks={tasks}/>
)}/>
<Route path='/create' render={() => (
<Create/>
)}/>
<Route path='/overview' render={() => (
<Overview tasks={tasks}/>
)}/>
<Route path='/about' render={() => (
<About/>
)}/>
<Route path="/500" component={InternalServer} status={500}/>
<Route path="*" component={NotFound} status={404}/>
</Switch>
</div>
);
}
}
export default App;
/* server.js */
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const mysql = require('mysql');
const app = express();
const selectAllTasks = 'SELECT * FROM TASKS';
const selectAllTasksByID = 'SELECT * FROM TASKS WHERE TASK_ID=?';
const selectAllProperties = 'SELECT * FROM PROPERTIES';
const insertTasks = 'INSERT INTO TASKS SET ?';
const delTasks = 'DELETE FROM TASKS WHERE TASK_ID=?';
const conn = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '******',
database: 'task_db'
});
conn.connect(error => {
if (error) throw error;
console.log(`Connected!`);
});
console.log(conn);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cors());
app.get('/', (request, response) => {
response.send('Go to /tasks to see tasks data');
});
app.get('/tasks/get', (request, response) => {
conn.query(selectAllTasks, (error, results) => {
if (error) {
return response.send(error);
}
else {
return response.json({
data: results
})
}
});
});
app.get('/properties/get', (request, response) => {
conn.query(selectAllProperties, (error, results) => {
if (error) {
return response.send(error);
}
else {
return response.json({
data: results
})
}
});
});
app.post('/tasks/create', (request, response) => {
let data = {
TASK_NAME: request.body.Name,
TASK_DESC: request.body.Desc,
TASK_LOCATION: request.body.Location,
ASSIGNED_TO: request.body.Assign
};
conn.query(insertTasks, data, (error, results, fields) => {
if (error) {
return response.send(error);
}
else {
response.send(JSON.stringify(results));
}
});
});
app.put('/tasks/update', (request, response) => {
/* Need help drafting the code... */
response.send('Tasks update!');
});
app.get('/tasks/:TASK_ID', (request, response) => {
conn.query(selectAllTasksByID, request.params.TASK_ID, (error, results) => {
if (error) {
return response.send(error);
}
else {
response.send(JSON.stringify(results));
}
});
});
app.delete('/tasks/delete:TASK_ID', (request, response) => {
const Id = {id: request.params.TASK_ID};
conn.query(delTasks, [request.body.TASK_ID], Id, (error) => {
if (error) {
return response.send(error);
}
else {
request.flash('Task Deleted Successfully!!! ' + 'ID: ' + request.params.TASK_ID);
response.send(JSON.stringify(results));
response.redirect('/overview');
}
});
});
app.listen(4000, () => {
console.log(`Tasks server listening on port 4000`)
});
/* Overview.js */
import React from 'react';
import TaskBreadcrumb from './TaskBreadcrumb.js';
/* https://dev.to/abdulbasit313/an-easy-way-to-create-a-customize-dynamic-table-in-react-js-3igg */
/* https://www.w3schools.com/howto/howto_js_todolist.asp */
import DoneOutlineIcon from '#material-ui/icons/DoneOutline';
import NotificationsActiveIcon from '#material-ui/icons/NotificationsActive';
import EditIcon from '#material-ui/icons/Edit';
import DeleteIcon from '#material-ui/icons/Delete';
/*import Modal from 'react-modal';*/
import EditModal from './EditModal.js';
import {Helmet} from "react-helmet";
class Overview extends React.Component {
renderTaskData() {
const tasks = this.props.tasks;
return tasks.map(task =>
<tr key={task.TASK_ID}>
<td>{task.TASK_ID}</td>
<td>{task.TASK_NAME}</td>
<td>{task.TASK_DESC}</td>
<td>{task.TASK_LOCATION}</td>
<td>{task.TASK_COMPLETE}</td>
<td>{task.ASSIGNED_TO}</td>
<td>
<button id={task.TASK_ID} className="w3-button" title="Edit Task" onClick={this.onTaskEdit}> <EditIcon /> </button>
<button id={task.TASK_ID} className="w3-button" title="Delete Task" onClick={this.onTaskDelete(task.TASK_ID)}> <DeleteIcon /> </button>
<button id={task.TASK_ID} className="w3-button" title="Task complete" onClick={this.onTaskComplete}> <DoneOutlineIcon /> </button>
<button id={task.TASK_ID} className="w3-button" title="Task reminder" onClick={this.onTaskRemind}> <NotificationsActiveIcon /> </button>
</td>
</tr>
)
}
onTaskComplete() {
console.log("Task Complete!")
}
onTaskDelete(task) {
const tasks = this.props;
console.log("Task Deleted!")
let data = {
Id: task.TASK_ID
};
fetch('/tasks/delete:TASK_ID', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}).then(function(response) {
if (response.status >= 400) {
throw new Error("Bad response from server");
}
return response.json();
}).then(function(data){
if (data === "success") {
alert('Task record deleted successfully!')
}
}).catch(function(error){
console.log(error)
});
}
onTaskEdit() {
console.log("Task Edited!")
}
onTaskRemind() {
console.log("Task Reminder alert!")
}
render() {
return (
<div className="w3-container">
<Helmet>
<title>Reroot Task Scheduler - Task Overview</title>
</Helmet>
<TaskBreadcrumb/>
<div className="w3-card-4">
<div className="w3-container w3-green">
<h1 className="w3-animate-top">Task Overview:</h1>
</div>
<h3>Property Name:</h3>
<div className="w3-responsive">
<table className="w3-table-all w3-card-4 w3-hoverable w3-centered">
<thead>
<tr className="w3-pale-yellow">
<th>Task ID</th>
<th>Task Name</th>
<th>Task Description</th>
<th>Task Location</th>
<th>Status</th>
<th>Person responsible</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{this.renderTaskData()}
</tbody>
</table>
</div>
<EditModal/>
</div>
</div>
);
}
}
export default Overview;

Related

Not able to delete my column from my Mysql table

I tried everything I think but no able to delete data from my mysql table using axios.delete with ProjectId (table ids).
Here's my code for where I declared my function, and as you can see I am passing the function through props
import React from "react";
import Projects from "../Projects/Projects";
import "./pluseProjects.css";
import {IoIosAddCircleOutline} from "react-icons/io"
import { Link } from "react-router-dom";
import {BiChevronLeftCircle,BiChevronRightCircle} from "react-icons/bi"
import {IoRefreshCircleOutline} from "react-icons/io5";
import axios from "axios";
export default function PluseProjects() {
const [addNewProjects, setAddNewProjects ] = React.useState(false)
const [getQuery,setGetQuery] = React.useState({
projectList:[]
})
function onStateChange() {
setAddNewProjects(!addNewProjects)
}
function getProjectList() {
axios.get(`http://localhost:3060/projects`)
.then((response) => response.data)
.then(response2 => {
setGetQuery({projectList : response2})
})
}
function onDeleteId(ProjectId) {
axios.delete(`http://localhost:3060/deleteprojects/${ProjectId}`)
getProjectList();
}
return(
<div className="Section-Projects" >
<div className="top-projects">
<h1>My Projects </h1>
<button onClick={getProjectList} className="Refresh"><IoRefreshCircleOutline /></button>
<Link to={addNewProjects?'/AddProjects':""} ><button className="Add-newProject" onClick={onStateChange}><IoIosAddCircleOutline /></button></Link>
</div>
<div className="Projects">
<button className="arrowLeft"><BiChevronLeftCircle /></button>
<div className="Single">
{getQuery.projectList.map((gettingQuery) =>
<Projects
onHandleDelete={onDeleteId(gettingQuery.ProjectId)}
ProjectName={gettingQuery.ProjectName}
Discription={gettingQuery.Discription}
git={gettingQuery.git}
Img={gettingQuery.Img}
/>
)}
</div>
<button className="arrowRight"><BiChevronRightCircle /></button>
</div>
</div>
)
};
Here is my server.js code - I am telling SQL to delete this column with some ProjectId:
const express = require('express');
const cors = require('cors')
const PORT = 3060;
const db = require('./Database')
const bodyParser = require('body-parser');
const { response } = require('express');
const app = express();
app.use(cors());
app.use(bodyParser.json());
app.get('/projects', (req,res) => {
const TASK_QUERY = `SELECT * FROM newproject`;
db.query(TASK_QUERY , (err, response) => {
if(err) res.status(404).send('something is wrong')
else res.send(response)
})
});
app.post('/addProjects', (req,res) => {
const ADD_QUERY = `INSERT INTO newproject (ProjectName,Discription,git,Img) VALUES('${req.body.ProjectName}','${req.body.Discription}','${req.body.git}','${req.body.Img}')`;
db.query(ADD_QUERY, (err) => {
if (err) console.log(err)
else res.send('Query added successfully')
})
} );
app.delete('/deleteprojects/:ProjectId', (req,res) => {
console.log(req.params.ProjectId)
const DELETE_TASK = `DELETE FROM newProjects WHERE ProjectId = ${req.params.ProjectId}`
db.query(DELETE_TASK, (err,res) => {
if (err) console.log(err)
})
})
app.listen(PORT, () => {
console.log('app is listening on port 3000')
})
And here's where I am calling my function - I think my props management is all right. Am I calling the function the wrong way?
import React from "react";
import "./Projects.css"
import {RxCrossCircled} from "react-icons/rx"
export default function Projects(props) {
return(
<div className="Project" >
<div className="Image">
<img src={props.Img} alt=""/>
<button className="cross" onClick={props.ProjectId}><RxCrossCircled /></button>
</div>
<div className="Bottom">
<h3>{props.ProjectName}</h3>
<p>{props.Discription}</p>
{props.git}
</div>
</div>
)
};
If you see a http call in the network tab when you trigger the function (clicking the delete button etc). That means your frontend(react part) is working fine. Also i clearly see that you are missing an res.send() statement in your delete route in your server.js.
app.delete('/deleteprojects/:ProjectId', (req, res) => {
console.log(req.params.ProjectId)
const DELETE_TASK = `DELETE FROM newProjects WHERE ProjectId = ${req.params.ProjectId}`
db.query(DELETE_TASK, (err, res) => {
if (err) console.log(err)
res.status(200).send({}) // you missed this
})
})
Your onHandleDelete is not being used in the Projects component. And the ProjectId is not passed as a prop. In the PluseProjects you immediately call the onDeleteId function you should call it via an anonymous function.
PluseProjects
{
getQuery.projectList.map((gettingQuery) => (
<Projects
onHandleDelete={() => onDeleteId(gettingQuery.ProjectId)} // () =>
ProjectName={gettingQuery.ProjectName}
Discription={gettingQuery.Discription}
git={gettingQuery.git}
Img={gettingQuery.Img}
/>
));
}
Projects
export default function Projects(props) {
return (
<div className="Project">
<div className="Image">
<img src={props.Img} alt="" />
<button className="cross" onClick={props.onHandleDelete}> // change ProjectId to onHandleDelete
<RxCrossCircled />
</button>
</div>
<div className="Bottom">
<h3>{props.ProjectName}</h3>
<p>{props.Discription}</p>
{props.git}
</div>
</div>
);
}

Confused about changing state in a certain way

I have a page in NextJS for editing an sql row and sending it back. I have fetched all the rows from the table and then have set the state to be the single row which matches the query parameter in the useRouter hook. Now, after I have edited the data in the row, what is a good way to POST it back to the backend?
Below is my React code:
import { React, useEffect, useState } from "react";
import { useRouter } from "next/dist/client/router";
const axios = require("axios");
export default function Edit() {
const [data, setData] = useState([]);
const router = useRouter();
const onSubmitHandler = (e) => {
e.preventDefault();
axios.post("/api/cards", data);
};
useEffect(() => {
const fetchData = async () => {
await axios
.get("/api/cards")
.then((res) => {
if (res.data) {
res.data.map((element) => {
if (element.ID == router.query.card) {
setData(element);
return;
}
return;
});
}
})
.catch((err) => {
console.log(err);
});
};
if (router.isReady) {
fetchData();
}
}, [router.isReady, router.query.card]);
return (
<form onSubmit={onSubmitHandler}>
<label htmlFor="front">Front</label>
<input
defaultValue={data.Front}
id="front"
onChange={(e) => setData({ ...data, Front: e.target.value })}
></input>
<label htmlFor="back">Back</label>
<input
defaultValue={data.Back}
id="back"
onChange={(e) => setData({ ...data, Back: e.target.value })}
></input>
<button type="submit">Add Word</button>
</form>
);
}
Below is my backend code
if (req.method === "POST") {
const { front, back, type } = req.body.data;
const id = uuidv4();
db.query(
`INSERT INTO deck VALUES('${front}', '${back}', '${type}', '${id}')`,
(err, rows, fields) => {
if (!err) {
res.json(rows);
} else {
console.log(err);
}
}
);
}
Its good to post the edited data after submiting the form..
const onSubmitHandler = async (e) => {
e.preventDefault();
try {
await axios.post("/api/cards", data);
// react-toast or something like that to indicate the ui the form is updated
// then the control flow of the application
} catch (error){
console.error(error)
}
};
One thing I notice over here is you're using POST for the update. Try HTTP PUT instead of POST.
And regarding your answer: You can send modified data in your API call like you're already maintaining the state of the updated data. Then you can just send that row to the API call and handled that in your backend code.
const onSubmitHandler = (e) => {
e.preventDefault();
axios.put("/api/cards/:id", data); // modify the API URL and append dynamic ID of the record.
};

Trying to retrive JSON Array through fetch in react native but JSON parse error:Unreconised token "<"

In the code,i am fetching the token from expo-secure-store,later fetching the API data from fetchdata function.But unfortunately error "unrecognized token" is displayed.
After the error is displayed,the API call returns JSON Array data.Unable to do data map in react native to TradeCard Component.
import { StatusBar } from 'expo-status-bar';
import {React,useState,useEffect} from 'react';
import TradeCard from './TradeCard';
import { StyleSheet, Text, View,TextInput,TouchableOpacity,ScrollView,ActivityIndicator } from 'react-native';
import * as SecureStore from 'expo-secure-store';
export default function Trades()
{
const [ data,setData] = useState([]);
const [ isLoading,setLoading] = useState(true);
const [user,setUser] = useState('');
const [token,setToken] = useState('');
const fetchTokens = async () => {
try {
const user = await SecureStore.getItemAsync('user');
const token = await SecureStore.getItemAsync('token');
setUser(user);
setToken(token);
if (user && token)
{
fetchData();
}
else
{
}
} catch (e) {
alert('Error',e);
}
}
useEffect(()=>{ fetchTokens()},[]);
const fetchData = async () => {
setLoading(true);
fetch('https://tradecoaster.herokuapp.com/api/v1/listTrades/'+user+'/',
{
method:'GET',
headers:{
'Accept':'application/json',
'Content-Type':'application/json',
'Authorization':'token '+token
}
})
.then(res => res.json())
.then((res)=>{
console.log('Data',res);
setData(res);
setLoading(false);
})
.catch((error)=>{
setLoading(false);
alert(error);
console.error("Error",error);
});
}
return(
<ScrollView>
<View>
{isLoading && data.length==0 ? <ActivityIndicator size="large" color="#0000ff" /> :
<Text>No Trades</Text>
}
</View>
</ScrollView>
);
}```

How to pass data from a function in react native component

I have created a Banner Component in React Native and now im trying to add data from a function (seperate .js file) in this component. I want to fetch the data on the inital load from my Home Screen but i dont know how to pass the data from my function. I hope you can help me.
This is my code:
home.js
export function HomeScreen() {
{/*This will cause an error*/}
const [item, setItem] = React.useState([]);
React.useEffect(() => {
{/*Function where i fetch my Data from API */}
getbannerdata().then(res => {
setItem(res)
})
console.log(item)
}, [])
return (
<SafeAreaProvider>
<SafeAreaView style={style.container}>
<View>
{/*Banner Component with Data param*/}
<Banner data={item} />
<Text>Home</Text>
</View>
</SafeAreaView>
</SafeAreaProvider>
);
}
My function:
bannerdata.js
export const getbannerdata = () => {
const [data, setData] = React.useState([])
console.log('Test')
fetch('http://192.168.178.46:8000/intranet/messages/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.then(res => res.json())
.then(res => {
console.log(res)
setData(res)
})
.catch(error => console.log(error));
return data;
};
I hope you can help me.
You should use useState in your component only not in the function where you fetch data.
bannerdata.js
export const getbannerdata = () => {
return fetch('http://192.168.178.46:8000/intranet/messages/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
};
home.js
import { getbannerdata } from './bannerdata'; //import getbannerdata function and you should provide the path of bannerdata.js
export function HomeScreen() {
const [item, setItem] = React.useState([]);
React.useEffect(() => {
{/*Function where i fetch my Data from API */}
getbannerdata()
.then(res => res.json())
.then(res => {
console.log(res)
setItem(res);
});
.catch(error => console.log(error));
}, []);
return (
<SafeAreaProvider>
<SafeAreaView style={style.container}>
<View>
{/*Banner Component with Data param*/}
<Banner data={item} />
<Text>Home</Text>
</View>
</SafeAreaView>
</SafeAreaProvider>
);
}
Thank you for your help.
This is my final solution.
Its a little bit different but now it works as expected
bannerdata.js
import * as React from 'react';
function getbannerdata(){
return fetch ('http://192.168.178.46:8000/intranet/messages/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.then((res) => res.json())
.then((resData) => {
return resData;
})
.catch(error => console.log(error))
};
export { getbannerdata }
home.js
import {getbannerdata} from './home/bannerdata.js';
export function HomeScreen() {
const [item, setItem] = React.useState([]);
React.useEffect(() => {
getbannerdata()
.then(res => setItem(res))
}, []);
return (
<SafeAreaProvider>
<SafeAreaView style={style.container}>
<View>
{/*Banner Component with Data param*/}
<Banner data={item} />
<Text>Home</Text>
</View>
</SafeAreaView>
</SafeAreaProvider>
);
}

Pass database data from express.js server to react.js component

This is a react app with an express.js backend. I have a mysql database connected to my server.js file and it seems to be connected fine. My issue is I want to pass that data to my react app and display it there.
My server.js database connection
app.get('api/listitems', (req, res) => {
connection.connect();
connection.query('SELECT * from list_items', (error, results, fields) => {
if (error) throw error;
res.send(results)
});
connection.end();
});
So this should grab the 'list_items' records from the database
Below is my react.js code. I would like to display the records under the grocery list h3.
import React, { Component } from 'react';
import './App.scss';
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: ['first item']
};
}
render() {
return (
<div className="App">
<h3>Grocery List</h3>
{this.state.data}
</div>
);
}
}
export default App;
I know this is a simple concept but I am new to backend development. The tutorials I have found have gotten me to this point, but I have had an issue finding one that simply explains how to pass and display data from the backend to frontend.
**index.js**
import React from 'react';
import { render } from 'react-dom';
import App from './components/app';
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux';
import store, { history } from './store';
const route = (
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
)
render(route,document.getElementById('app'))
**action/listItemAction.js**
export const ListItemSuccess = (data) => {
return {type: 'GET_LIST_ITEMS'};
}
export const getListItems = () => {
return (dispatch) => {
return axios.get('http://localhost:5000/api/listitems')
.then(res => {
dispatch(ListItemSuccess(res));
})
.catch(error=>{
throw(error);
})
};
}
**reducers/listItems.js**
const listItems = (state = [], action) => {
switch(action.type){
case 'GET_LIST_ITEMS':
return action.res.data;
default:
return state;
}
}
export default listItems;
**store.js**
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk'
import listItems from './reducers/listItems.js';
const store = createStore(listItems, compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : f => f
));
export default store;
**App.js**
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import './App.scss';
import getListItems from './action/listItemAction.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: true,
};
}
componentWillMount() {
this.props.getListItems().then(() => {
this.setState({data: this.props.listItems, isLoading:false});
}).catch(error => {
throw(error);
});
}
render() {
return (
<div className="App">
<h3>Grocery List</h3>
{this.state.isLoading ? <p>Loading...</p>
: this.state.error ? <p>Error during fetch!</p>
: (
<ul>
this.state.data.map(item => <li>{item}</li>)
</ul>
)}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
listItems: state.listItems
};
};
const mapDispatchToProps = (dispatch) => {
return {
getListItems: bindActionCreators(getListItems, dispatch),
};
};
export default connect(mapStateToProps,mapDispatchToProps)(App);
You want to make a GET request to your backend to asynchronously fetch the data. If you want the data when your App component first mounts, you can use fetch in componentDidMount to call to your backend endpoint. Here's an example, with a loading fallback and basic error handling:
class App extends Component {
state = {
data: [],
loading: true,
error: false
}
...
componentDidMount() {
// Pick whatever host/port your server is listening on
fetch('localhost:PORT/api/listitems')
.then(res => { // <-- The `results` response object from your backend
// fetch handles errors a little unusually
if (!res.ok) {
throw res;
}
// Convert serialized response into json
return res.json()
}).then(data => {
// setState triggers re-render
this.setState({loading: false, data});
}).catch(err => {
// Handle any errors
console.error(err);
this.setState({loading: false, error: true});
});
}
render() {
return (
<div className="App">
<h3>Grocery List</h3>
// The app will render once before it has data from the
// backend so you should display a fallback until
// you have data in state, and handle any errors from fetch
{this.state.loading ? <p>Loading...</p>
: this.state.error ? <p>Error during fetch!</p>
: (
<ul>
this.state.data.map(item => <li>{item}</li>)
</ul>
)}
</div>
);
}
}
fetch won't reject on HTTP error status (404, 500), which is why the first .then is a little odd. The .catch will log the response here with the status, but if you want to see the error message from the server, you'll need to do something like this:
if (!res.ok) {
return res.text().then(errText => { throw errText });
}
See See https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch for more information, or explore other data fetching libraries like axios.