Issue
Hello
I have developed a frontend React project which requests resources and logic to a SpringBoot REST API. I recently implemented file upload, and the form I have created using React always fails on the first try, but when I click it again and upload a different file (which file is irrelevant, it's not the file causing this), it successfully uploads the file via POST with a Binary file as a payload.
The first request has a payload of 'undefined'.
React Form:
const UPDATE_USER_URL = 'http://localhost:8080/users/update-user-details';
const UPLOAD_FILE_URL = 'http://localhost:8080/image-files';
class UpdateUserForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: localStorage.getItem("username"),
location: "",
bio: ""
};
this.onSubmit = this.onSubmit.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value
});
}
onFileChangeHandler = (e) => {
e.preventDefault();
this.setState({
selectedFile: e.target.files[0]
});
const formData = new FormData();
formData.append('file', this.state.selectedFile);
const USER_UPLOAD_FILE_URL = UPLOAD_FILE_URL + "/" + this.state.username;
fetch(USER_UPLOAD_FILE_URL, {
method: 'POST',
headers: {
"Authorization": localStorage.getItem("token")
},
body: formData
}).then(res => {
if(res.ok) {
console.log(res.data);
alert("File uploaded successfully.")
}
});
};
onSubmit(event) {
event.preventDefault();
const payload = {
"username": this.state.username,
"location": this.capital_letter(this.state.location),
"bio": this.state.bio
};
fetch(UPDATE_USER_URL, {
method: 'PUT',
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": localStorage.getItem("token")
},
body: JSON.stringify(payload)
})
.then(response => response.json())
.then((data) => {
console.log(data);
});
}
//https://www.w3resource.com/javascript-exercises/javascript-basic-exercise-50.php
capital_letter(str) {
str = str.split(" ");
for (var i = 0, x = str.length; i < x; i++) {
str[i] = str[i][0].toUpperCase() + str[i].substr(1);
}
console.log(str)
return str.join(" ");
}
generateUploadUrl(username) {
}
render() {
return (
<div className="outer-div-container">
<div>
<AppNavbar/>
<div id="form-container">
<div id="form-div">
<h5 id="form-heading">Update Details</h5>
<br />
<div className="outer-div-container">
<form onSubmit={this.onSubmit}>
<label className="form-label" id="top-form-label">
Location:
<br />
<input
className="form-input"
//Taumatawhakatangihangakoauauotamateaturipukakapikimaungahoronukupokaiwhen
maxLength="85"
//No min length as places with 1 letter e.g: A, S.
name="location"
type="text"
value={this.state.location}
onChange={this.handleInputChange} />
</label>
<br />
<label className="form-label">
Bio:
<br />
<input
className="form-input"
minLength="3"
name="bio"
type="text"
value={this.state.bio}
onChange={this.handleInputChange} />
</label>
<label>Upload Your File </label>
<input type="file" className="form-control" name="file" onChange={this.onFileChangeHandler}/>
<br />
<input id="form-submit" type="submit" value="Submit" />
</form>
<div className="form-group files color">
<label>Upload Your File </label>
<input type="file" className="form-control" name="file" onChange={this.onFileChangeHandler}/>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default UpdateUserForm;
Controller:
@RestController
@RequestMapping("image-files")
@AllArgsConstructor
@CrossOrigin("*")
public class ImageFileController {
ImageFileService service;
@GetMapping(value = "/{username}")
public byte[] downloadImageFile(@PathVariable String username) {
return service.downloadImageFile(username);
}
}
Any help would be greatly appreciated, I am completely stumped, thanks.
Solution
In your onFileChangeHandler function you are setting the file to the selectedFile state and then immediately access it again like
formData.append('file', this.state.selectedFile);
You cannot set something to the react state and access it again on the next line, this is because setState works asynchronously in react. Which means if you want to get the latest set value from react state, you need to wait for the next re-render to happen. Otherwise you will only get the previously set value from the state, and in your case its undefined. So in you function, pass the file data directly to the formData. Try the below code
onFileChangeHandler = (e) => {
e.preventDefault();
const fileData = e.target.files[0];
this.setState({
selectedFile: fileData
});
const formData = new FormData();
formData.append('file', fileData);
const USER_UPLOAD_FILE_URL = UPLOAD_FILE_URL + "/" + this.state.username;
fetch(USER_UPLOAD_FILE_URL, {
method: 'POST',
headers: {
"Authorization": localStorage.getItem("token")
},
body: formData
}).then(res => {
if(res.ok) {
console.log(res.data);
alert("File uploaded successfully.")
}
});
};
Answered By - Vishnu Sajeev

0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.