First time useState not showing up on UI - reactjs

My simplified code is below.
Goal: To display the names of the images that the user selects. The user selects an image, it is saved to a service, and I use a "put" request to get the images for that particular object, and then display the name. These steps are required for getting the names.
Issue: When I first select images via the "file upload button" (Form.Control), the image name(s) do not display on the #1 (commented as "#1: HERE!", at the bottom of code). When I go back and select more images, then #1 correctly displays the previously selected images AND the newly selected images (which is the correct behavior). My problem is that on the first selection, the image name is NOT being displayed.
const MyComponent = () => {
const [fileNames, setFileNames] = useState({});
// a service that calls gets the file names from objectId
const getFileNames = (objectId) => {
const input = { objectId: objectId };
fetch(service(), {
method: "PUT",
headers: {..(stuff here), "Content-Type": "application/json"},
body: JSON.stringify(input)
})
.then( res => { res.json() })
.then( resJson => {
if( //resJson has errors) {
//log error msg
else {
// problem is here????
setFileNames(resJson.results);
return resJson;
}
})
.catch( err => //stuff here)
}
const handleFileChange = (e) => {
// saves selected file(s) to particular objectId
saveFile(event.target.files), props.objectId, props.somethingelse);
getFileNames(props.objectID);
}
const showName = (file) => {
return (
<span> {file.name} </span>
)
}
return (
<div>
<Form.Control
type="file" multiple
onChange={ e=> {handleFileChange(e)} }
{/* bunch of the stuff here */}
/>
{/* ***********#1 - HERE!*************** */}
{fileNames.map( file => file.showName(file) )}
</div>
)
}

I suspect you are not waiting for the file to be saved before you get the filename. That's why perhaps the first save is empty?
const MyComponent = () => {
const [fileNames, setFileNames] = useState([]);
// This should be an array be default since you map over it later down
// make this an async function
const getFileNames = async (objectId) => {
const input = { objectId: objectId };
let resJson;
try {
const result = await fetch(service(), {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(input),
});
resJson = await result.json();
} catch (error) {
// TODO: error handling
}
if (resJson.error) { // TODO: fix me
//log error msg
} else {
setFileNames(resJson.results);
}
};
// this too should be an asnyc function
const handleFileChange = async (event) => {
// I assume saveFile is an async function
await saveFile(event.target.files, props.objectId, props.somethingelse);
// save the file here ^ and wait for it to finish saving
await getFileNames(props.objectID);
// after you saved the file get the filename now
};
const showName = (file) => {
return <span> {file.name} </span>;
};
return (
<div>
<Form.Control
type="file"
multiple
onChange={(e) => {
handleFileChange(e);
}}
/>
{/* bunch of the stuff here */}
{fileNames.map((file) => file.showName(file))}
</div>
);
};

Related

React: How to use received json data from firebase to make list of array?

I want to make a list of user details by filling the form with name, email, designation, phone & image input field, I've saved the form data in an object and sent the form data to it's parent using props addedUser(userData);, I'm using this addedUser prop in the parent component to send the data to the firebase and then use the same fetched data to make a list of users in array.
I've made loadedData empty array simply wanna push the data into it but the responseData.json() doesn't give me anything, the data is being saved to firebase perfectly but I'm facing problems using it.
Please check the code here and also the <Users /> component code where I'm trying to make the list:
Parent:-
function App() {
const [userData, setUserData] = useState([]);
const fetchData = useCallback(async () => {
try {
const responseData = await fetch(
"https://react-users-db-default-rtdb.asia-southeast1.firebasedatabase.app/users.json"
);
const data = responseData.json();
console.log(data);
const loadedData = [];
for (const key in data) {
loadedData.push({
key: key,
userName: data[key].userName,
userEmail: data[key].userEmail,
userDesignation: data[key].userDesignation,
usePhone: data[key].usePhone,
userImage: data[key].userImage,
});
}
console.log(loadedData);
setUserData(loadedData);
} catch (err) {
console.log(err);
}
}, []);
useEffect(() => {
fetchData();
}, [fetchData]);
async function recieveUserData(users) {
const responseData = await fetch(
"https://react-users-db-default-rtdb.asia-southeast1.firebasedatabase.app/users.json",
{
method: "POST",
body: JSON.stringify(users),
headers: {
"Content-Type": "application/json",
},
}
);
const data = await responseData.json();
console.log(data);
}
return (
<main>
<div className="form__wrap">
<AddUserForm addedUser={recieveUserData} />
</div>
<div className="user__wrap">
{userData.length > 0 ? (
<Users newUser={userData} />
) : (
<p>No user found</p>
)}
</div>
</main>
);
}
Users Component:
export default function Users({ newUser }) {
console.log(newUser);
return (
<div className="usercard__wrap">
{newUser.map((el, i) => {
return (
<UserCard
key={i}
name={el.userName}
email={el.userEmail}
designation={el.userDesignation}
phone={el.userPhone}
image={el.userImage}
/>
);
})}
</div>
);
}
Data is going to firebase:-
But responseData.json() is giving me this, I can't see my user object to access:-
In your fetchData function you need to await responseData.json().
const data = await responseData.json();

React-dropzone-uploader : 422 Unprocessable Entity with fastapi upload

We are using react dropzone uploader to upload video with fastapi's
UploadFile
function
Below is the code
const MyUploader = () => {
// called every time a file's `status` changes
const handleChangeStatus = ({ meta, file }, status) => { console.log(status, meta, file) }
// receives array of files that are done uploading when submit button is clicked
const handleSubmit = (files, allFiles) => {
files.map(file => uploadFile(file))
}
return (
<Dropzone
onChangeStatus={handleChangeStatus}
onSubmit={handleSubmit}
accept="video/*"
/>
)
}
and
function uploadFile (file) {
// Initial FormData
console.log("file inside uploadfile",file)
let formData = new FormData();
formData.append("file_obj", file);
const clientid=localStorage.getItem("client_id");
console.log("clientid",clientid)
return axios.post(`${apiEndpoint}/upload?clientId=${clientid}`, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
}
below is the error getting
and backend code is
#router.post("/upload")
async def Videoupload(response: Response, clientId: str = None, file_obj: UploadFile = File(...)):
try:
if validate_filename(file_obj.filename):
response.status_code=409
return "video with filename already exists"
upload_video(clientId,file_obj)
response.status_code = 201
return "file uploaded"
except Exception as error:
print("Error in uploading", str(error))
response.status_code = 500
return "Error in uploading"
It could be great if anybody can help with this
Correct way of using RDU is to call upload api in
getUploadParams
const MyUploader = () => {
const getUploadParams = ({ file, meta }) => {
const body= new FormData()
body.append('file_obj', file)
const clientid=localStorage.getItem("client_id");
console.log("clientid",clientid)
return { url: `${apiEndpoint}/upload?clientId=${clientid}`, body }
}
// called every time a file's `status` changes
const handleChangeStatus = ({ meta, file }, status) => { console.log(status, meta, file) }
// receives array of files that are done uploading when submit button is clicked
const handleSubmit = (files, allFiles) => {
console.log(files.map(f => f.meta))
allFiles.forEach(f => f.remove())
}
return (
<Dropzone
getUploadParams={getUploadParams}
onChangeStatus={handleChangeStatus}
onSubmit={handleSubmit}
accept="video/*"
/>
)
}

React POST request, how to reconcile a timing error?

I have a react file tied to an express/node backend and SQL database. My backend is functioning correctly, all routes are verified with postman and the app has the ability to get, post, update, and delete. However, I am running into an issue with my front end now, specifically regarding my POST request.
Every time I make a post request the server/database are being updated correctly with the new applicant, which I can see populate the back end, but I am receiving the following error on the front end "Cannot read properties of undefined (reading 'store')" pertaining to my function labeled "TableList"
Somehow the TableList function which has the role of extrapolating only the unique stores that applicants are assigned too is picking up an "undefined" value for the new store assignment whenever a POST request is made. What is most confusing to me is that if I then reload the page manually the front end displays correctly. Is this a timing issue related to async?
Below is my main file where all state is held - relevant functions are TableList and those containing the markup New Vehicle Form
import { useState, useEffect, useImperativeHandle } from "react";
import useFetch from "../Components/Fetch/fetch";
import List from "../Components/Sections/list";
import Intro from "../Components/Sections/intro";
import SearchForm from "../Components/Forms/searchForm";
import AddForm from "../Components/Forms/addForm";
import UpdateForm from "../Components/Forms/updateForm";
import { parseDate } from "../Components/Utils/index";
const Home = () => {
/* DATE & TIME FORMAT */
var today = new Date();
const displaytime = parseDate(today);
/*INITIAL STATE*/
const { data, setData, isPending } = useFetch(
`http://localhost:5000/api/applicants`
);
/*NEW VEHICLE FORM: TOGGLE FORM DISPLAY*/
const [showAddForm, setShowAddForm] = useState(false);
const handleAddForm = () => {
setShowAddForm(!showAddForm);
};
/*NEW VEHICLE FORM: POST REQUEST, DECLARING STATE*/
const initialFormState = {
store: "",
first_name: "",
last_name: "",
position: "",
recruiterscreen_status:"",
testing_status:"",
interview_status:"",
backgroundcheck_status:"",
drugscreen_status:"",
paperwork_status:"",
date_in: "",
currentdate: displaytime,
notes:"",
};
const [formData, setFormData] = useState({ ...initialFormState });
/*NEW VEHICLE FORM: POST REQUEST, UPDATING STATE*/
const handleFormChange = (event) => {
const { name, value } = event.target;
setFormData({
...formData,
[name]: value,
});
};
/*NEW VEHICLE FORM: POST REQUEST, TRIGGER RERENDER*/
const confirmpost = (applicant) => {
setData([...data, applicant])
console.log(data)
};
/*NEW VEHICLE FORM: POST REQUEST, SUBMIT TO SERVER*/
const handleFormSubmit = (event) => {
event.preventDefault();
const applicant = formData;
console.log(applicant);
fetch(`http://localhost:5000/api/applicants/`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(applicant),
})
.then((response) => response.json())
.then((response) => console.log("Added Successfully"))
.then((applicant) => confirmpost(applicant))
.then(()=>handleAddForm())
.catch((error) => console.log("Form submit error", error));
setFormData({ ...initialFormState });
};
/*DELETE APPLICANT: FRONT END RERENDER*/
const deleteApplicant = (id) => {
const updatedTable = data.filter((item) => item.applicant_id != id);
setData(updatedTable);
};
/*DELETE APPLICANT: SERVER REQUEST*/
const handleDelete = (id, stock) => {
fetch(`http://localhost:5000/api/applicants/${id}`, {
method: "DELETE",
})
.then((response) => console.log("Deleted Applicant"))
.then(() => deleteApplicant(id));
};
/*UPDATE FORM: TOGGLE FORM DISPLAY, ALSO GRAB USER ID*/
const [showUpdateForm, setShowUpdateForm] = useState(false);
const [selectedApplicant, setSelectedApplicant] = useState(null)
const [selectedApplicantName, setSelectedApplicantName] = useState(null)
const handleUpdateForm = (applicant_id, first_name,last_name) => {
setSelectedApplicant(applicant_id)
setSelectedApplicantName(first_name + " "+ last_name)
setShowUpdateForm(!showUpdateForm);
console.log(`Show Form: ${showUpdateForm}`)
};
/*UPDATE FORM: DECLARE INITIAL STATE*/
const initialStatusState = {
recruiterscreen_status:null,
testing_status: null,
interview_status:null,
backgroundcheck_status: null,
drugscreen_status: null,
paperwork_status:null,
notes:null,
};
/*UPDATE FROM: CHANGE APPLICANT STATE*/
const [statusData, setStatusData] = useState({ ...initialStatusState });
const handleStatusChange = (event) => {
const { name, value } = event.target;
setStatusData({
...statusData,
[name]: value,
});
};
/*UPDATE FORM: SUMBIT TO SERVER*/
const handleUpdate = (id) => {
fetch(`http://localhost:5000/api/applicants/${id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(statusData),
})
.then((response) => response.json())
.then(() => confirmUpdate(id))
.then((response) => console.log(`Updated Successfully to
recruiterscreen_status: ${statusData.recruiterscreen_status},
testing_status: ${statusData.testing_status},
interview_status: ${statusData.interview_status},
backgroundcheck_status: ${statusData.backgroundcheck_status},
drugscreen_status: ${statusData.drugscreen_status},
paperwork_status: ${statusData.paperwork_status},
notes:${statusData.notes},`));
setStatusData({ ...initialStatusState });
};
/*UPDATE FORM: FRONT END RERENDER*/
const confirmUpdate = (id) => {
const updatedTable = data.map((item) =>
item.applicant_id != id
? item
: {
...item,
recruiterscreen_status: statusData.recruiterscreen_status,
testing_status: statusData.testing_status,
interview_status: statusData.interview_status,
backgroundcheck_status: statusData.backgroundcheck_status,
drugscreen_status: statusData.drugscreen_status,
paperwork_status: statusData.paperwork_status,
notes:statusData.notes,
}
);
setData(updatedTable);
handleUpdateForm(id)
};
/* NOTES POP UP */
const [notesIsOpen, setNotesIsOpen] = useState(false)
const togglePopup = () => {
setNotesIsOpen(!notesIsOpen)
}
/*LIST OF ACTIVE STORES*/
const unique = (value, index, self) => {
return self.indexOf(value) === index;
};
const TableList = (data) => {
const list = data.map((element) => element.store);
const uniquelist = list.filter(unique).sort();
console.log(uniquelist)
return uniquelist;
};
const stores = TableList(data)
/*RUN*/
return (
<div>
<Intro displaytime={displaytime} />
<div className="add-applicant">
<button className="add-applicant-btn" onClick={handleAddForm}>
Add Applicant
</button>
</div>
<SearchForm data={data} setData={setData} />
{showAddForm ? (
<AddForm
formData={formData}
setFormData={setFormData}
handleFormChange={handleFormChange}
handleFormSubmit={handleFormSubmit}
/>
) : null}
{showUpdateForm ? (
<UpdateForm data={data} selectedApplicant={selectedApplicant} selectedApplicantName={selectedApplicantName} handleUpdateForm={handleUpdateForm} statusData={statusData} handleStatusChange={handleStatusChange} handleUpdate={handleUpdate} />
) : null}
<hr></hr>
{!isPending ? (
stores.map((element) => (
<div>
{" "}
<List
cut={element}
data={data}
isPending={isPending}
handleDelete={handleDelete}
handleUpdate={handleUpdate}
handleStatusChange={handleStatusChange}
showUpdateForm={showUpdateForm}
handleUpdateForm={handleUpdateForm}
togglePopup={togglePopup}
notesIsOpen={notesIsOpen}
TableList={TableList}
/>
</div>
))
) : (
<div>Loading</div>
)}
</div>
);
};
export default Home;
In the fetch chain the logging step which injects an undefined into the chain.
The logging step needs to pass on its input data:
fetch(`http://localhost:5000/api/applicants/`, { }) // Elided
.then((response) => response.json())
.then((response) => {
console.log("Added Successfully")
return response
)
.then((applicant) => confirmpost(applicant))

react-mic record audio and send the blob as mp3/wav to backend

Basically I want to record audio and I'm using react-mic for this but it gives back blob but I want mp3 or wav file to send to the backend. How to POST blob file to the server?
This is my code in App.js
import React from "react";
import { ReactMic } from "react-mic";
import $ from "jquery";
import { findDOMNode } from "react-dom";
import "./App.css";
class App extends React.Component {
handleDisplayForStart = () => {
const startBtn = findDOMNode(this.refs.startBtn);
$(startBtn).addClass("d-none");
const stopBtn = findDOMNode(this.refs.stopBtn);
$(stopBtn).removeClass("d-none");
};
handleDisplayForStop = () => {
const stopBtn = findDOMNode(this.refs.stopBtn);
$(stopBtn).addClass("d-none");
const processBtn = findDOMNode(this.refs.processBtn);
$(processBtn).removeClass("d-none");
};
constructor(props) {
super(props);
this.state = {
blobURL: null,
recordedBlob: null,
record: false,
};
}
startRecording = () => {
this.setState({ record: true });
this.handleDisplayForStart();
};
stopRecording = () => {
this.setState({ record: false });
this.handleDisplayForStop();
};
onData(recordedBlob) {
console.log("chunk of real-time data is: ", recordedBlob);
}
onStop = (recordedBlob) => {
console.log(recordedBlob.blobURL);
const blobURL = recordedBlob.blobURL;
this.setState({ blobURL: blobURL });
this.onUpload();
return recordedBlob.blobURL;
};
onUpload = (recordedBlob) => {
// var form = new FormData();
// form.append("file", recordedBlob);
// fetch("http://localhost:3000/audio", {
// // content-type header should not be specified!
// method: "POST",
// body: form,
// })
// .then(function (response) {
// return response.text();
// })
// .then(function (text) {
// console.log(text); // The text the endpoint returns
// })
// .catch((error) => console.log(error));
};
render() {
return (
<div className="App">
<ReactMic
visualSetting="frequencyBars"
// mimeType='audio/mp3'
record={this.state.record}
className="d-none"
onStop={this.onStop}
onData={this.onData}
/>
<button
ref="startBtn"
className="start-btn"
onClick={this.startRecording}
type="button"
>
START
</button>
<button
ref="stopBtn"
className="stop-btn concentric-circles d-none"
onClick={this.stopRecording}
type="button"
>
STOP
</button>
<button
ref="processBtn"
className="process-btn d-none"
onClick={this.onUpload}
>
Processing..
</button>
<br />
<audio src={this.state.blobURL} controls />
</div>
);
}
}
export default App;
I tried various things from medium blogs and different StackOverflow answers but anything doesn't work correctly.
This may be a bit late, i also came across this problem and i also couldn't find a solution, sharing the solution so it may help others.
code for sending recorded blob file using react-mic to server,
const onStop = (blob) => {
const formData = new FormData();
// if you print blob in console you may get details of this obj
let blobWithProp = new Blob([blob["blob"]], blob["options"]);
formData.append("file", blobWithProp);
const postRequest = {
method: "POST",
body: formData,
};
fetch("http://127.0.0.1:5000/audio_out/", postRequest)
.then(async (res) => {
const data = await res.json();
console.log(data);
if (!res.ok) {
const err = (data && data.message) || res.status;
return Promise.reject(err);
}
})
.catch((err) => {
console.log(err);
});
};
Here onStop() is the callback function which is executed when recording stopped.
On your commented part of your code you are sending recorded blob file directly. I don't know much about it, but if you log the received file on console you may see it is an object file containing blob, options, etc. So, I think we need to create a new Blob file from that. I am just a beginner in web development, may be i am wrong. But the above code solved the problem.

501 Not Implemented error in small web app

I am trying to upload images to an S3 bucket with react and expressjs. When I attempt to upload the image I get a 501 Not Implemented Error. I am using axios to contact the end point I created in the server code.
My react code:
class FileUpload extends Component {
state = {
file: null
};
submitFile = (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('file', this.state.file[0]);
axios.post(`test-upload`, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(response => {
// handle your response;
}).catch(error => {
// handle your error
});
}
handleFileUpload = (event) => {
this.setState({file: event.target.files});
}
render () {
return (
<form onSubmit={this.submitFile}>
<input label='upload file' type='file' onChange=
{this.handleFileUpload} />
<button type='submit'>Send</button>
</form>
);
}
}
export default FileUpload;
My server code:
const uploadFile = (buffer, name, type) => {
const params = {
ACL: 'public-read',
Body: buffer,
Bucket: process.env.S3_BUCKET,
ContentType: type.mime,
Key: `${name}.${type.ext}`
};
return s3.upload(params).promise();
};
app.use('/', (req,res) =>{
res.send(JSON.stringify({ greeting: `Hello!` }));
});
// Define POST route
app.post('/test-upload', (request, response) => {
const form = new multiparty.Form();
form.parse(request, async (error, fields, files) => {
if (error) throw new Error(error);
try {
const path = files.file[0].path;
const buffer = fs.readFileSync(path);
const type = fileType(buffer);
const timestamp = Date.now().toString();
const fileName = `bucketFolder/${timestamp}-lg`;
const data = await uploadFile(buffer, fileName, type);
return response.status(200).send(data);
} catch (error) {
return response.status(400).send(error);
}
});
});
This was done by following a guide on the internet but there seems to be something missing that I just can't figure out.
Figured it out in the end,
axios.post(/test-upload,
should have been
axios.post(http://localhost:3000/test-upload,

Resources