Confused about changing state in a certain way - mysql

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.
};

Related

How to pass updated set State value in axios request as params

I'm a beginner in react native, I'm trying to get user information from mysql database through an axios API get request.
Once logged in, I stored email address in AsyncStorage and later want to use that email address from AsyncStorage as params or parameters to get the user details.
I wrote a code which set initial state of the setState as 'na'. Please help me how I can pass the email address from AsyncStorage as params or parameters.
Here is my code.
// to load email address
const [SessionEmail, setSessionEmail] = useState('na');
// to load users info
const [users, setUsers] = useState([]);
useFocusEffect(
React.useCallback(() => {
getUsername();
getUsersInfoFromAPI();
}, [])
);
// to get the session username from localstorage
const getUsername = async () => {
try {
const username = await AsyncStorage.getItem('Username')
if (username !== null) {
setSessionEmail(username);
}
} catch (e) {
console.log(e);
}
}
// API Calling user details
const getUsersInfoFromAPI = async () => {
await axios.get(`https://myapi.co.in/api/user/?email=${SessionEmail}`)
.then(response => {
setUser(response.data);
})
.catch(error => {
console.log(error);
});
}
After the page is rendered, and I load page from metro, I can see the parameters have been sent to server.
Update your code in this way:
useFocusEffect(
React.useCallback(() => {
getUsername();
}, [])
);
Instead of saving your email to state, sent it to function directly but if you are using it for other reason you can still save it but call function while getting username from AsyncStorage with username parameter like below.
// to get the session username from localstorage
const getUsername = async () => {
try {
const username = await AsyncStorage.getItem('Username')
if (username !== null) {
getUsersInfoFromAPI(username);
}
} catch (e) {
console.log(e);
}
}
// API Calling user details
const getUsersInfoFromAPI = async (email) => {
await axios.get(`https://myapi.co.in/api/user/?email=${email}`)
.then(response => {
setUser(response.data);
})
.catch(error => {
console.log(error);
});
}
const [users, setUsers] = useState([]);
here you can use like this
const [users, setUsers] = useState();
hope this will help you

How to implement edit form with file upload

Trying to update a form without uploading a new image. I'm
using multer for the image upload. it works very well when i
create a form.
I'm using reactJs for frontend and node for the server side.
This is the front end code with react
import React, { useState, useEffect } from 'react';
import { useParams } from "react-router-dom";
import useFetch from "./fetch";
function EditForm() {
const { id } = useParams();
const { contestant: form, error, isPending } =
useFetch("http://localhost:5000/dashboard/form_single/" +
id);
const [name, setName] = useState('');
const [address, setAddress] = useState('');
const [fileName, setFileName] = useState('');
useEffect(() => {
setName(form.full_name);
setAddress(form.home_address);
}, [form])
const editForm = async (id) => {
try {
const formData = new FormData();
formData.append("name", name);
formData.append( "home_address", address);
formData.append("image", fileName);
const myHeaders = new Headers();
myHeaders.append("jwtToken", localStorage.jwtToken);
await
fetch(`http://localhost:5000/dashboard/form_update/${id}`, {
method: "PUT",
headers: myHeaders,
body: formData,
});
} catch (err) {
console.error(err.message);
}
};
const onChangeFile = e => {
setFileName(e.target.files[0]);
}
return (
<div>
{ isPending && <div>Loading...</div> }
{ error && <div>{ error }</div> }
<form encType="multipart/form-data"
onSubmit={() => editForm(form.form_id)}>
<input
type="text"
className="form-control"
value={name || ''}
onChange={e => setName(e.target.value)}
/>
<input
type="text"
className="form-control"
value={address || ''}
onChange={e => setAddress(e.target.value)}
/>
<input
type="file"
id="update"
name="image"
onChange={onChangeFile}
/>
<button type ="submit" >Save</button>
</form>
<div>
<img
alt="contestant"
src= {`http://localhost:5000/upload/${form.passport}`}
className="rounded-circle" style={{width: "100px",
height: "100px"}}/>
</div>
</div>
);
}
export default EditForm;
UNFORTUNATELY I GET Cannot read properties of undefined (reading 'filename'). I've tried to make multer image upload optional but it did'nt work. The code bellow is the api.
This is the server side code. Nodejs
router.put("/form_update/:id", upload.single('image'), async(req,
res) => {
try {
const { id } = req.params;
const image = req.file.filename;
const { name, home_address } = req.body;
const updateForm = await pool.query("UPDATE form SET
full_name = $1, home_address = $2, passport = $3 WHERE
form_id = $4
RETURNING *", [name, home_address, image, id]);
res.json("Form was updated");
} catch (err) {
console.error(err.message);
}
});
how do i not always have to change image everytime i need to edit a form.
on the server, check if fields are provided, and then store values for each, and construct query dynamically, and when done checking, execute query
you could list fields in an array and then iterate them and construct query and values against req.body
you could also add some validation (check if there is id etc., you could add that on the front-end as well)
try this:
router.put("/form_update/:id", upload.single('image'), async(req, res) => {
try {
// fields. same as in req.body
const fields = ['full_name', 'home_address', 'something', 'else'];
// store values
const values = [];
// dynamic query string
let stmt = [];
const {id } = req.params;
// add some validation
if(!id) {
console.error('no id..');
return res.json({msg:"err: no id"});
}
const image = req.file ? req.file.filename : '';
// build query
fields.map((field)=>{
if(req.body[field]) {
values.push(req.body[field]);
stmt.push(`${field} = $${values.length}`);
}
});
// check image, as it's not in req.body
if(image) {
values.push(image);
stmt.push(`passport = $${values.length}`);
}
// no data..end
if(!values.length) {
console.log('no data..');
return res.json({msg:'no data..'});
}
// finish
stmt = "UPDATE form SET " + stmt.join(', ');
values.push(id);
stmt += ` WHERE form_id = $${values.length}`;
stmt += ' RETURNING *';
const updateForm = await pool.query(stmt, values);
res.json({msg:"Form was updated"});
} catch (err) {
console.error(err.message);
}
});

Change number of servings on click (React Hooks - API)

I'm working on a recipe site using API from a third party and want to change the number of servings (which is output from the API data) when clicking the + & - button. I tried assigning the output serving amount <Servings>{recipe.servings}</Servings> in a variable and useState to update it but it kept showing errors. I would appreciate any help (preferably using react Hooks). Thanks :)
Here is my code:
const id = 716429;
const apiURL = `https://api.spoonacular.com/recipes/${id}/information`;
const apiKey = "34ac49879bd04719b7a984caaa4006b4";
const imgURL = `https://spoonacular.com/cdn/ingredients_100x100/`;
const {
data: recipe,
error,
isLoading,
} = useFetch(apiURL + "?apiKey=" + apiKey);
const [isChecked, setIsChecked] = useState(true);
const handleChange = () => {
setIsChecked(!isChecked);
};
return (
<Section>
<h2>Ingredients</h2>
<ServingsandUnits>
{recipe && (
<ServingsIncrementer>
<p>Servings: </p>
<Minus />
<Servings>{recipe.servings}</Servings>
<Plus />
</ServingsIncrementer>
)}
<ButtonGroup>
<input
type="checkbox"
id="metric"
name="unit"
checked={isChecked}
onChange={handleChange}
/>
<label htmlFor="male">Metric</label>
</ButtonGroup>
</ServingsandUnits>
</Section>
};
My custom hook is called useFetch:
const useFetch = (url) => {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const abortCont = new AbortController();
fetch(url, { signal: abortCont.signal })
.then((res) => {
if (!res.ok) {
// error coming back from server
throw Error("Could not fetch the data for that resource");
}
return res.json();
})
.then((data) => {
setIsLoading(false);
setData(data);
setError(null);
})
.catch((err) => {
if (err.name === "AbortError") {
console.log("Fetch aborted");
} else {
// auto catches network / connection error
setIsLoading(false);
setError(err.message);
}
});
return () => {
abortCont.abort();
};
}, [url]);
return { data, isLoading, error };
};
export default useFetch;

How to print json api data in reactjs

I'm fetching json api details through GET request and trying to print it. Getting an error:
Error in the console is Uncaught ReferenceError: allUsers is not defined
const Dashboard = ({status, juser}) => {
const [allUsers, setAllUsers] = React.useState([]);
const id = juser.actable_id;
console.log(id); //getting id here as 1
const getAllusers = () => {
axios
.get(`http://localhost:3001/user/${id}`, { withCredentials: true })
.then((response) => {
console.log(response.data);
setAllUsers(response.data);
})
.catch((error) => {
console.log(" error", error);
});
};
React.useEffect(() => {
getAllusers();
}, []);
{allUsers.map((job_seeker, index) => {
return (
<div>
<p>{job_seeker.name}</p>
</div>
);
})}
}
export default Dashboard;
I'm new to react. Any help is appreciatable.
const [state, setState] = React.useState([]);
the state is where your data is located and setState is function to reset the state from anywhere,
so on your code,
const [jobseekers, allUsers] = React.useState([]); // change string to array
jobseekers is the variable where your data is located and allUsers is the function to store data into state.
set data to state using allUsers function,
const getAllusers = () => {
axios
.get(`http://localhost:3001/user/${id}`, { withCredentials: true })
.then((response) => {
allUsers(response.data);
})
.catch((error) => {
console.log(" error", error);
});
};
and map from jobseekers
{jobseekers.map((job_seeker, index) => {
return (
<div>
<p>{job_seeker.name}</p>
</div>
);
})}
Also I would suggest to rename your state and setState as,
const [allUsers, setAllUsers] = React.useState([]);
You didn't pass the value of response to allUsers, instead, you just created a new variable. So change
const allUsers = response.data;
to:
allUsers(response.data)
Besides, you can also improve the way that you have used useState. You have initialized it as an empty string while you'll probably store an array from response in jobseekers. So, initialize it as an empty array.
const [jobseekers, allUsers] = React.useState([]);

ipfs.add is not working for ipfs client v44.3.0 how can I resolve this?

This is my code in App.js, and its always returning an "Unhandeled Rejection Type error saying that ipfs.add(...). then is not a function.
import React, { Component } from 'react';
import './App.css';
var ipfsAPI = require('ipfs-http-client')
var ipfs = ipfsAPI({host: 'localhost', port: '5001', protocol:'http'})
class App extends Component {
saveTestBlobOnIpfs = (blob) => {
return new Promise(function(resolve, reject) {
const descBuffer = Buffer.from(blob, 'utf-8');
ipfs.add(descBuffer).then((response) => {
console.log(response)
resolve(response[0].hash);
}).catch((err) => {
console.error(err)
reject(err);
})
})
}
render() {
return (
<div className="App">
<h1>IPFS Pool</h1>
<input
ref = "ipfs"
style = {{width: 200, height: 50}}/>
<button
onClick = {() => {
console.log("Upload Data to IPFS");
let content = this.refs.ipfs.value;
console.log(content);
this.saveTestBlobOnIpfs(content).then((hash) => {
console.log("Hash of uploaded data: " + hash)
});
}}
style = {{height: 50}}>Upload Data to IPFS</button>
</div>
);
}
}
export default App;
Do I need to add an async function or something, I'm fairly new to js so any help would greatly appreciated. I just don't know how to change the ipfs.add to make my code work.
I have also followed the same tutorial and ran into the same problem. The ipfs.add function does not accept a call function anymore. More information on that here: https://blog.ipfs.io/2020-02-01-async-await-refactor/
The solution is turn your saveTestBlobOnIpfs function into an async/await function. Like this:
saveTestBlobOnIpfs = async (event) => {
event.preventDefault();
console.log('The file will be Submitted!');
let data = this.state.buffer;
console.log('Submit this: ', data);
if (data){
try{
const postResponse = await ipfs.add(data)
console.log("postResponse", postResponse);
} catch(e){
console.log("Error: ", e)
}
} else{
alert("No files submitted. Please try again.");
console.log('ERROR: No data to submit');
}
}