React Ant Design multiple files upload doesn't work - reactjs

I'm in the process of sending multiple files from "React.js" by formData.append() to a backend.
At the backend(Spring boot), I was able to see that multiple files were saved well with postman.
The problem occurred in React.
(I'm using "Ant Design" that is React UI Library.)
Below is the source that append files to formdata with extra data.
const formData = new FormData();
formData.append('webtoonId', this.state.selectedToonId);
formData.append('epiTitle', this.state.epiTitle);
formData.append('eFile', this.state.thumbnail[0].originFileObj);
for( let i = 0; i< this.state.mains.length ; i++){
formData.append('mFiles', this.state.mains[i].originFileObj);
}
uploadEpi(formData)
uploadEpi() is POST API.
Below is about state.
this.state = {
toons: [],
epiTitle :'',
thumbnail : [],
mains : [],
selectedToonID : ''
}
When I submit, Text and single file are stored in the DB normally, but only multiple files cannot be saved.
There was no error. Just multiple files didn't be saved.
The state "mains" is configured as shown below.
I guess it's because I'm using Ant Design incorrectly.
(Ant Design : https://ant.design/components/upload/)
Why I guessed so, because when I add multiple attribute to <Dragger> like below,
<Dragger onChange={this.onChangeMain} beforeUpload={() => false} multiple={true}>
the state "mains" multiple files became undefined.
Below is onChange={this.onChangeMain}
onChangeMain=({ fileList })=> {
this.setState({ mains : fileList }, function(){
console.log(this.state)
});
}
The bottom line is, I want to know how to upload multiple files through <Upload> (or <Dragger>) in "React Ant Design."
I don't know what should I do.
this is my github about this project.
I'd appreciate with your help. thx.

const [loading, setLoading] = useState<boolean>(false);
const [fileList, setFileList] = useState<any[]>([]);
const [/* fileListBase64 */, setFileListBase64] = useState<any[]>([]);
const propsUpload = {
onRemove: (file:any) => {
const index = fileList.indexOf(file);
const newFileList:any = fileList.slice();
newFileList.splice(index, 1);
return setFileList(newFileList)
},
beforeUpload: (file:any) => {
setFileList([...fileList, file]);
return false;
},
onChange(info:any) {
setLoading(true);
const listFiles = info.fileList;
setFileList(listFiles);
const newArrayFiles = listFiles.map((file:any) => file.originFileObj? (file.originFileObj) : file );
const anAsyncFunction = async (item:any) => {
return convertBase64(item)
}
const getData = async () => {
return Promise.all(newArrayFiles.map((item:any) => anAsyncFunction(item)))
}
getData().then(data => {
/* setFileSend(data) */
setFileListBase64(data);
setLoading(false);
// console.log(data);
});
},
directory: true,
fileList: fileList,
};
const convertBase64 = (file:File) => {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.readAsDataURL(file)
fileReader.onload = () => {
resolve(fileReader?.result);
}
fileReader.onerror = (error) => {
reject(error);
}
})
}
const handleDeleteListFiles = () => {
setFileList([]);
setFileListBase64([]);
}

It seems like you are overriding the value of mFiles.
const formData = new FormData();
formData.append('webtoonId', this.state.selectedToonId);
formData.append('epiTitle', this.state.epiTitle);
formData.append('eFile', this.state.thumbnail[0].originFileObj);
let mFiles = [];
for( let i = 0; i< this.state.mains.length ; i++){
mFiles[i] = this.state.mains[i].originFileObj;
}
formData.append('mFiles', mFiles)
uploadEpi(formData)

Maybe this can work: formData.append('mFiles[]', mFiles)
If you add [] to the string it should not overwrite but add to the array

Related

Discord.js push slash commands

I recently started writing Discordbots and just can't seem to get anywhere pushing the slash commands. I already have a handler file (pushSlash.js) but for some reason the commands are never loaded or I get an error in the console (mostly simply this: chalk.blue is not a function). My bot also doesn't get the badge that it supports slash commands.
Can anyone help me further?
Here is my code (pushSlash.js):
module.exports = (client) => {
const fs = require('fs');
const { PermissionsBitField } = require('discord.js');
const { Routes } = require('discord-api-types/v9');
const { REST } = require('#discordjs/rest');
const AsciiTable = require('ascii-table');
const table = new AsciiTable().setHeading('Slash Commands', 'Stats').setBorder('|', '=', "0", "0");
const TOKEN = process.env.BOT_TOKEN;
const CLIENT_ID = process.env.CLIENT_ID;
const rest = new REST({ version: '9' }).setToken(TOKEN);
import( 'chalk').then(chalk => {
const slashCommands = [];
fs.readdirSync('/home/container/src/slashCommands/').forEach(async dir => {
const files = fs.readdirSync(`/home/container/src/slashCommands/${dir}/`).filter(file => file.endsWith('.js'));
for(const file of files) {
const slashCommand = require(`/home/container/src/slashCommands/${dir}/${file}`);
slashCommands.push({
name: slashCommand.name,
description: slashCommand.description,
options: slashCommand.options ? slashCommand.options : null,
default_permission: slashCommand.default_permission ? slashCommand.default_permission : null,
default_member_permissions: slashCommand.default_member_permissions ? PermissionsBitField.resolve(slashCommand.default_member_permissions).toString() : null
});
if(slashCommand.name) {
client.slashCommands.set(slashCommand.name, slashCommand);
table.addRow(file.split('.js')[0], '✅');
} else {
table.addRow(file.split('.js')[0], '⛔');
}
}
});
console.log(chalk.blue(table.toString()));
(async () => {
try {
await rest.put(
process.env.GUILD_ID ?
Routes.applicationGuildCommands(CLIENT_ID, process.env.GUILD_ID) :
Routes.applicationCommands(CLIENT_ID),
{ body: slashCommands }
);
console.log(chalk.green('Successfully registered application commands.'));
} catch (error) {
console.log(error);
}
})();
});
};
I've already tried everything possible, but since I'm relatively new to discord.js, I don't know that much yet either.
Actually everything should work and exactly 2 different commands should be loaded, but I only get error messages or the handler was loaded on console but nothing is displayed on Discord.
first download chalk#4.1.2 with
npm install chalk#4.1.2
and import chalk normally.
const chalk = require('chalk')
There your code modified version:
module.exports = (client) => {
const fs = require('fs');
const { PermissionsBitField } = require('discord.js');
const { Routes } = require('discord-api-types/v9');
const { REST } = require('#discordjs/rest');
const AsciiTable = require('ascii-table');
const table = new AsciiTable().setHeading('Slash Commands', 'Stats').setBorder('|', '=', "0", "0");
const TOKEN = process.env.BOT_TOKEN;
const CLIENT_ID = process.env.CLIENT_ID;
const rest = new REST({ version: '9' }).setToken(TOKEN);
// Imported chalk normally
const chalk = require('chalk')
// removed `import( 'chalk').then(chalk => {})`
const slashCommands = [];
fs.readdirSync('/home/container/src/slashCommands/').forEach(async dir => {
const files = fs.readdirSync(`/home/container/src/slashCommands/${dir}/`).filter(file => file.endsWith('.js'));
for(const file of files) {
const slashCommand = require(`/home/container/src/slashCommands/${dir}/${file}`);
slashCommands.push({
name: slashCommand.name,
description: slashCommand.description,
options: slashCommand.options ? slashCommand.options : null,
default_permission: slashCommand.default_permission ? slashCommand.default_permission : null,
default_member_permissions: slashCommand.default_member_permissions ? PermissionsBitField.resolve(slashCommand.default_member_permissions).toString() : null
});
if(slashCommand.name) {
client.slashCommands.set(slashCommand.name, slashCommand);
table.addRow(file.split('.js')[0], '✅');
} else {
table.addRow(file.split('.js')[0], '⛔');
}
}
});
console.log(chalk.blue(table.toString()));
(async () => {
try {
await rest.put(
process.env.GUILD_ID ?
Routes.applicationGuildCommands(CLIENT_ID, process.env.GUILD_ID) :
Routes.applicationCommands(CLIENT_ID),
{ body: slashCommands }
);
console.log(chalk.green('Successfully registered application commands.'));
} catch (error) {
console.log(error);
}
})();
};

Lifecycle of useState hook in React.js

I have the following synchronism problem. Given that I know that the React useState hook is asynchronous, I run into the following: I'm downloading some images from Amazon S3, I manage to save it correctly in my hook: defaultSelfiePicture and depending on the weight of the image (or so I think) sometimes I get the images loaded correctly and sometimes not. I have tried to force state changes after I finish saving the object in my hook but it never renders the image, only if I change component and come back is when it is shown in the cases that it takes longer to load.
const [defaultSelfiePictures, setDefaultSelfiePictures] = useState([])
useEffect(() => {
if (savedUser.docs !== undefined) {
loadAllPictures()
}
}, [savedUser.docs.length])
const loadAllPictures = () => {
let p1 = loadUrlDefaultFrontPictures()
let p2 = loadUrlDefaultBackPictures()
let p3 = loadUrlDefaultSelfiePictures()
Promise.all([p1, p2, p3]).then(result => {
console.log('end all promises')
setTimestamp(Date.now())
})
}
const loadUrlDefaultSelfiePictures = async () => {
if (savedUser.docs.length > 0) {
let readedPictures = []
for (let i = 0; i < savedUser.docs.length; i++) {
if (
savedUser.docs[i].type === 'SELFIE'
//&& savedUser.docs[i].side === 'FRONT'
) {
if (
savedUser.docs[i].s3Href !== null &&
savedUser.docs[i].s3Href !== undefined
) {
const paramsKeyArray =
savedUser.docs[i].s3Href.split('')
let paramsKey = paramsKeyArray.pop()
let params = {
Bucket: process.env.REACT_APP_S3_BUCKET,
Key: paramsKey
}
await s3.getSignedUrl('getObject', params, function (err, url) {
readedPictures.push({
idKycDoc: savedUser.docs[i].idKycDoc,
name: 'selfie.jpeg',
type: savedUser.docs[i].type,
url: url
})
})
} else {
let urlPicture = savedUser.docs[i].localHref
let response = await axios.get(`${URL_IMG}${urlPicture}`, {
responseType: 'blob'
})
function readAsDataURL(data) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(data)
reader.onloadend = () => {
resolve(reader.result)
}
})
}
const base64Data = await readAsDataURL(response.data)
readedPictures.push({
idKycDoc: savedUser.docs[i].idKycDoc,
name: 'selfie.jpeg',
type: savedUser.docs[i].type,
url: `data:image/jpeg;base64,${base64Data.slice(21)}`
})
}
}
}
setDefaultSelfiePictures(readedPictures)
}
}
And I obtain this :
I can see that the hook has content, but that content is not updated until the next rendering of the component, also if I try to make any changes when I detect that the .length has changed it tells me that it is 0...
And right after the next render I get this:

How to push multiple images in an array?

I'm creating a React Native application. I want to create an image array because I need to upload them to the server. But when I upload multiple images they are not storing like an array. every time the imagesQueue array has only one image.
my code as follows.
const [filePath, setFilePath] = useState({
imagesQueue: []
});
const chooseFile = () => {
const options = {
title: 'Select an option',
storageOptions: {
skipBackup: true,
path: 'images',
},
};
ImagePicker.showImagePicker(options, (response) => {
// console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else {
// let source = response;
// You can also display the image using data:
let source = {
uri: 'data:image/jpeg;base64,' + response.data
};
setFilePath({
...filePath,
imagesQueue: [source],
});
console.log("stored item : " + filePath.imagesQueue);
}
});
};
How to store multiple images in the same state. Thanks in advance.
the data probably will store in formData - it's easy format for later passing it to BE.
firstly You need store somewhere those data:
const [selectedFiles, setSelectedFiles] = useState([]);
Later there is possibility to use .concat() - that function connects 2 arrays:
setSelectedFiles(((prevState) => prevState.concat(fileData)));
And in the last step, You need to pass those data to Your form:
const formData = new FormData();
for (let i = 0; i < selectedFiles.length; i++) {
formData.append('Files', selectedFiles[i].File);
}

React.js logging before operation is finished

onReaderLoad = (e) => {
var obj =JSON.parse(e.target.result)
this.setState(prevState => ({
datasource: [...prevState.datasource, obj]
}))
}
ReadFiles = () => {
let files = this.state.json_files;
for (let i of files){
var reader = new FileReader();
reader.onload = this.onReaderLoad;
reader.readAsText(i);
}
console.log(this.state.datasource)
}
getfolder = (e) => {
var files = e.target.files;
this.setState({
json_files: files
}, () => this.ReadFiles())
}
<input type="file" onChange={this.getfolder} multiple accept=".json" />
Here i am sharing my code.
What i am trying to do is i am reading all the json files from user input and looping them and storing it to react state.
Then inside ReadFiles() function i am logging the state data. But it is always coming empty data.
I think it calling first and then going to the loop.
I wants to log the datasource data from state inside ReadFiles() function after all Looping operation is done
Is there any way to do that ?
Please have a look
You can make use of instance variable in this case to keep track of whether you are processing last file or not. Once you know that last file is being processed, you can set doNextStep to true in state from callback of last processed file. Then in componentDidUpdate, you can do next step(i.e. console log or anything else).
class Example extends React.Component {
constructor(props){
super(props);
// to keep track of if last file is being processed
this.lastFile = false;
// doNextStep will tell us that all setState operations are completed or not
this.state = {
doNextStep: false,
}
}
componentDidUpdate(prevProps, prevState) {
if(prevState.doNextStep !== this.state.doNextStep && this.state.doNextStep) {
console.log(this.state.datasource)
}
}
onReaderLoad = (e) => {
var obj =JSON.parse(e.target.result)
this.setState(prevState => ({
datasource: [...prevState.datasource, obj]
}),
() => if(this.lastFile)) this.setState({doNextStep: true}))
}
ReadFiles = () => {
let files = this.state.json_files;
for (i=0; i<files.length; i++){
if(i == files.length - 1) this.lastFile = true
else this.lastFile = false
var reader = new FileReader();
reader.onload = this.onReaderLoad;
reader.readAsText(i);
}
}
}

Firebase upload multiple files and get status

I have a React form where the user can upload multiple files. These are stored in fileList
async function uploadFiles(id) {
try {
const meta = await storageUploadFile(fileList, id);
console.log(meta);
} catch (e) {
console.log(e);
}
}
This calls my helper function that uploads the files to Firebase
export const storageUploadFile = function(files, id) {
const user = firebase.auth().currentUser.uid;
return Promise.all(
files.map((file) => {
return storage.child(`designs/${user}/${id}/${file.name}`).put(file)
})
)
};
What I'd like is on calling uploadFiles, get the total filesize of all items, and then show the overall progress.
At the moment, my code is only returning the file status in an array on completion
[
{bytesTransferred: 485561, totalBytes: 485561, state: "success"},
{bytesTransferred: 656289, totalBytes: 656289, state: "success"}
]
This is the way i do it:
import Deferred from 'es6-deferred';
export const storageUploadFile = function(files, id) {
const user = firebase.auth().currentUser.uid;
// To track the remaining files
let itemsCount = files.length;
// To store our files refs
const thumbRef = [];
// Our main tasks
const tumbUploadTask = [];
// This will store our primses
const thumbCompleter = [];
for (let i = 0; i < files.length; i += 1) {
thumbRef[i] = storage.ref(`designs/${user}/${id}/${file.name}`);
tumbUploadTask[i] = thumbRef[i].put(files[i]);
thumbCompleter[i] = new Deferred();
tumbUploadTask[i].on('state_changed',
(snap) => {
// Here you can check the progress
console.log(i, (snap.bytesTransferred / snap.totalBytes) * 100);
},
(error) => {
thumbCompleter[i].reject(error);
}, () => {
const url = tumbUploadTask[i].snapshot.metadata.downloadURLs[0];
itemsCount -= 1;
console.log(`Items left: ${itemsCount}`)
thumbCompleter[i].resolve(url);
});
}
return Promise.all(thumbCompleter).then((urls) => {
// Here we can see our files urls
console.log(urls);
});
};
Hope it helps.

Resources