Reputation: 53
I'm quite new to react and redux and i (almost) always found a solution for untill but not for this !
So, for now, i have a file input somewhere in my react app where i can put a jpg file and another file input where i can put a pdf file. Nothing crazy here. But i need to handle those files to upload them later since it's like a multiple-pages form... I tried many things but can't find a working one.
Based on this : Store Input File Selected in Redux to Upload Later , the solution was looking too easy and is not working either...
I tried to handle the file (blob path, file object, file path...) in redux store but nothing is working. The request with Postman is working well btw, i can upload file with it.
Here is some code i did, which is not working right now (request is sent but file path is still NULL in my database). I'm using Symfony3 as backend. Other data from store is passed in my database, only files are not.
One of my inputs :
<input
type="file"
className="input-file"
name="flyer-pdf"
id="flyer-pdf"
onChange={this.handleChangeFilePath('flyer')}
accept=".pdf"
/>
My method to update my state :
handleChangeFilePath = prop => (event) => {
this.setState({
// Tried event.target.files[0]
[prop]: event.target.value,
});
};
Submited form :
handleSubmit = (logo, flyer) => {
this.props.flyerSetup(logo, flyer);
};
Method to call action :
const mapDispatchToProps = (dispatch) => {
return {
flyerSetup: (logo, flyer) => dispatch(appActions.flyerSetup(logo, flyer))
};
};
Called action :
export const flyerSetup = (logo, flyer) => ({
type: types.CLIENT_FLYER_SETUP,
logo: logo,
flyer: flyer
});
Called action in appReducer to update redux store :
case types.CLIENT_FLYER_SETUP:
return {
...state,
logo: action.logo,
flyer: action.flyer
};
Here is my action :
export const createTransaction = () => (getState) => {
const state = getState();
const data = {
logo: state.appReducer.logo,
flyer: state.appReducer.flyer
}
console.log(data);
return transactionService.postTransaction(data)
The console.log(data) is good, my store is nicely updated with the data i provide from the input, i always get the blob path/file path/file object but as i said, i'm not able to upload file into my server :(
P.s : I modified and cleaned the code to help it being more readable, feel free to ask for more ;)
Upvotes: 3
Views: 4327
Reputation: 53
Found a workaround, didn't realize i was using superagent at first (i'm not on this project since start), my problem was not the File object storage method but my headers in http requests :
static headers (headers = {}) {
return Object.assign({
// The application/json header was forced at every request
// "Content-Type": "application/json",
"Cache-Control": "no-cache",
"Pragma": "no-cache",
"Expires": "-1",
"Authorization": `Bearer ${sessionStorage.id_token}`
}, headers);
}
And my post request was acting like this :
static post (url, params, headers = {}) {
return request
.post(Api.prefix(url))
.set(Api.headers(headers))
.send(params);
}
Since application/json can't send files data (as far as i understood), i had to change how my last form was sending datas.
According to https://visionmedia.github.io/superagent/#multipart-requests , you can't mix .send and .attach and there's no way atm to do it...
So i modified my old post request, that's kinda annoying to have many .field() but it seems there's no alternative right now. At least it's working !
static post (url, params, headers = {}) {
if (url.match(/something/)) {
return request
.post(Api.prefix(url))
.set(Api.headers(headers))
.send(params);
} else {
return request
.post(Api.prefix(url))
.set(Api.headers(headers))
.field('x', params.x)
.field('x', params.x)
.field('x', params.x)
.field('x', params.x)
.field('x', params.x)
.field('x', params.x)
.field('x', params.x)
.field('x', params.x)
.field('x', params.x)
.field('x', params.x)
.attach('logo', params.logo)
.attach('flyer', params.flyer);
}
Also, i simply send the File object into my state (and then in my store, same way as before) :
handleChangeFilePath = prop => (event) => {
this.setState({
[prop]: event.target.files[0],
[prop + 'Preview']: event.target.files[0]
});
if ([prop][0] === 'flyer') {
this.updateNumberOfPages(event.target.files[0]);
}
};
Now my database is filled like i wanted and i can upload my files at the end of my form, way after i sent them in my store ! :)
Upvotes: 1