How to set Add two functions to 'onchange's in ReactJS - javascript

i am new to Reactjs, Still struggling to learn react. I have some problem related how i can call two functions in one onChange Event, I tried alot but did't get idea how it would be possible. Could You please help me. Thank You
Function 1
handleChange = ({ fileList }) => this.setState({ fileList });
Function 2
handleUpload = e => {
const reader = new FileReader();
const storeUser = JSON.parse(localStorage.getItem('user'));
reader.onload = function(upload) {
fetch(`http://..../api/s3/uploadtoaws`, {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
body: JSON.stringify({
userId: storeUser._id,
type: 'employee',
content: upload.target.result,
key: e.file.name,
oldKey: '',
}),
})
.then(response => response.json())
.then(res => {
console.warn(res);
});
// .done();
};
reader.readAsDataURL(e.file.originFileObj);
};
Event Implementation
<Upload
listType="picture-card"
fileList={fileList}
onPreview={this.handlePreview}
onChange={this.handleChange}
>

Just call the function inside JSX with specified argument, however it's important to use your handleUpload function as a currying function, so you will have access to both event and fileList.
onChange={this.handleUpload(someObj)}
handleUpload = ({ fileList }) => (e) => { // fileList is a field in someObj
this.setState({ fileList });
const reader = new FileReader();
const storeUser = JSON.parse(localStorage.getItem('user'));
reader.onload = function(upload) {
fetch(`http://..../api/s3/uploadtoaws`, {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
method: 'POST',
body: JSON.stringify({
userId: storeUser._id,
type: 'employee',
content: upload.target.result,
key: e.file.name,
oldKey: '',
}),
})
.then(response => response.json())
.then(res => {
console.warn(res);
});
// .done();
};
reader.readAsDataURL(e.file.originFileObj);
}

Related

including image in request body as binary data

I need to include the image as binary data in my uploading request using multipart form data, and it seems not working, any advise will be appreciated.
my code:
const [selectedFile, setSelectedFile] = useState(null);
const handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('selectedFile', new Blob([selectedFile], { type: 'application/octet-stream' }));
const data = {
uploadLink,
formData,
};
const headers = {
'Content-Type': 'application/octet-stream' ,
Accept: 'application/vnd.vimeo.*+json;version=3.4',
};
try {
await axios
.post(`${backendPostPath}/thumbnail-upload`, data, {
headers,
})
.then((response) => {
applyThumbnial();
console.log(response);
});
} catch (error) {
console.log(error);
}
};
const handleFileSelect = (event) => {
setSelectedFile(event.target.files[0]);
};
include formData as axios data parameter instead of your data object, so you can also include uploadLink in the formData:
const formData = new FormData();
formData.append('selectedFile', new Blob([selectedFile], { type: 'application/octet-stream' }));
formData.append('uploadLink', uploadLink)
//...
await axios
.post(`${backendPostPath}/thumbnail-upload`, formData, {
headers,
})

axios post request in react native and react app with JSON Stringify and blob

I am making an app in which I am calling an API end point in react native but I am getting this error but in the web app (its done with react) it doesn't show any error, Here is the web app code in react with typescript
try {
let result: any;
const criteriaWithNoFile = {
content: filterCriteria.content ? filterCriteria.content.trim() : '',
filterLimit: filterCriteria.filterLimit,
sorting: filterCriteria.sorting,
contractionOption: filterCriteria.contractionOption,
contentId: filterCriteria.contentId,
url: filterCriteria.url ? filterCriteria.url.trim() : ''
}
if (localStorage.getItem('currentUserToken')) {
dispatch({
type: LOADER,
payload: true
});
const formData = new FormData();
const jsonFilterCriteria = JSON.stringify(criteriaWithNoFile);
const blobFilterCriteria = new Blob([jsonFilterCriteria], {
type: 'application/json'
});
formData.append("filterData", blobFilterCriteria);
formData.append("filterFile", filterCriteria.selectedFile);
console.log('FormData', formData);
try {
result = await authAxios.post(`${process.env.REACT_APP_BASE_URL}/filter`, formData, {
headers: {
'Content-Type': 'multipart/mixed'
}
});
and here is the code I am trying in react native
const filterData = {
content: '',
filterLimit: 1000,
sorting: 'NATURAL',
contractionOption: 'LEAVE_CONTRACTION',
contentId: '',
url:
'https://stackoverflow.com/questions/37552973/get-the-time-zone-with-react-native',
};
const data = new FormData();
const jsonFilter = JSON.stringify(filterData);
const blobFilter = new Blob([jsonFilter], {
type: 'application/json',
});
data.append('filterData', jsonFilter);
data.append('filterFile', selectedFile);
await axios
.post('https://capi.beebl.io/filter', data , {
headers: {
'Content-Type': 'multipart/mixed',
},
})
.then((res) => console.log(res))
.catch((err) => console.log(err));
Can anyone help me what I am doing wrong....
I fixed it by making a separate API for FileUpload and FilterData

Testing functions calls inside callback with jest - React-native -

I'm testing the behavior of a function with a success api call, i managed to mock the fetch response, but the function inside then callback are not called, even if console.log showing the function is going inside the callback.
My test is failing here:
Here is the function im testing:
tryUserLogin() {
this.setState({loading: true});
const randomPassword = Math.random()
.toString(36)
.slice(-8);
const email = this.state.inputEmail;
const name = this.state.inputName;
const formData = new FormData();
formData.append('email', email);
formData.append('name', name);
formData.append('password', randomPassword);
const query = Util.urlForAddUser();
fetch(query, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data',
},
body: formData,
})
.then(response => response.json())
.then(responseJson => {
if (responseJson.code === 200) {
firebase.analytics().logEvent('userSuccessfulLogIn', {
userId: responseJson.response.id,
});
const userData = responseJson.response;
console.log('userData',userData) // <==== i can see this in console
this.storeUserData(userData, name);
this.setState({loading: false});
this.handleModalVisibility();
this.props.handelAddComment();
console.log('finish')
} else {
Alert.alert(
this.props.t('common:title_error'),
this.props.t('common:error'),
);
this.setState({loading: false});
}
})
.catch(error => {
firebase.crashlytics().log(
`error tryUserLogin
LoginModal===>> ${error.message}`,
);
Alert.alert(
this.props.t('common:title_error'),
this.props.t('common:error'),
);
this.setState({loading: false});
});
}
And here is the test:
it('testing tryUserLogin code 200 case', async () => {
global.FormData = require('FormData');
global.fetch = jest.fn();
const userData = {
code: 200,
response: {
id: 1,
email: 'test+1234567890#t.com',
},
};
const name = 'test';
const email = 'test#t.com';
const spyStoreUserData = jest.spyOn(instance, 'storeUserData');
const spyHandelModalVisibility = jest.spyOn(
instance,
'handleModalVisibility',
);
fetch.mockImplementation(() => {
return Promise.resolve({
status: 200,
json: () => {
return Promise.resolve({
...userData,
});
},
});
});
instance.setState({inputName: name});
instance.setState({inputEmail: email});
await instance.tryUserLogin();
expect(spyStoreUserData).toBeCalledWith(userData.response, name);
expect(fetch.mock.calls[0][0]).toBe('testQuery');
expect(instance.state.loading).toBe(false);
expect(spyHandelModalVisibility).toBeCalled();
expect(mockHandelAddComment).toBeCalled();
});

What happens when Axios makes a post request?

I'm building an App using reactjs and I'm questioning axios.
I have an axios.post
and following that I call a function
this.props.onChangeStep1()
with the way it is written...am I safe ?
Will this.props.onChangeStep1() always wait for res.data to be full ?
onChangeHandler = event => {
console.log(event.target.files[0]);
this.setState(
{
selectedFile: event.target.files[0],
fileName: event.target.files[0].name,
loaded: 0
},
() => {
console.log(this.state.selectedFile);
console.log(this.state.loaded);
const formData = new FormData();
formData.append("file", this.state.selectedFile);
axios
.post(`/upload`, formData, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then(res => {
console.log(res);
console.log(res.data);
});
this.props.onChangeStep1(); //<---- Will this wait for res.data ?
}
);
No. It won't wait. You should put it into .then:
onChangeHandler = event => {
console.log(event.target.files[0]);
this.setState(
{
selectedFile: event.target.files[0],
fileName: event.target.files[0].name,
loaded: 0
},
() => {
console.log(this.state.selectedFile);
console.log(this.state.loaded);
const formData = new FormData();
formData.append("file", this.state.selectedFile);
axios
.post(`/upload`, formData, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then(res => {
console.log(res);
console.log(res.data);
this.props.onChangeStep1();
});
}
In your example onChangeStep will be executed before the result from axios.
You can call this.props.onChangeStep1() inside .then() block:
axios
.post(`/upload`, formData, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then(res => {
console.log(res);
console.log(res.data);
this.props.onChangeStep1();
});
Or you can use async/await
postData = async () => {
const formData = new FormData();
formData.append("file", this.state.selectedFile);
try {
const result = await axios.post(`/upload`, formData, /* all your headers..*/)
this.props.onChangeStep1(); // this line will be executed after post request
} catch(error){
// do something with error.
}
}
}
onChangeHandler = event => {
this.setState(
{
selectedFile: event.target.files[0],
fileName: event.target.files[0].name,
loaded: 0
},
this.postData)
}

How to Fetch API (POST) using one single url but with each 4 different parameters

Okay, I am still new in Javascript. As per title, how to fetch a single API url but with 4 different parameters. My goal is to display 4 different categories as the result
Example (I have 4 different categories):
const category = [1,2,3,4];
I want to make each category calls for an api
Method 1
To call category 1:
const url = 'http://www.myapiurl.com/thisapi';
const parameter = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=1`
};
fetch(url, options)
.then(response => response.json())
.then(object => {})
To call category 2:
const url = 'http://www.myapiurl.com/thisapi';
const parameter = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=2`
};
fetch(url, options)
.then(response => response.json())
.then(object => {})
To call category 3:
const url = 'http://www.myapiurl.com/thisapi';
const parameter = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=3`
};
fetch(url, options)
.then(response => response.json())
.then(object => {})
To call category 4:
const url = 'http://www.myapiurl.com/thisapi';
const parameter = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=4`
};
fetch(url, options)
.then(response => response.json())
.then(object => {})
Or maybe I can simplify them a bit like this:
Method 2
const parameter1 = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=1`
};
const parameter2 = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=2`
};
const parameter3 = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=3`
};
const parameter4 = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=4`
};
Promise.all([
fetch(url,parameter1).then(value => value.json()),
fetch(url,parameter2).then(value => value.json()),
fetch(url,parameter3).then(value => value.json()),
fetch(url,parameter4).then(value => value.json()),
])
.then((value) => {
console.log(value)
//json response
})
.catch((err) => {
console.log(err);
});
But all of these are very redundant and uneccesarry repetition. What if I have 50 categories? How do I simplify all of these Fetch API calls? Please give me an enlightment. Thanks in advance
You can take it a step further. Since your method, headers and part of the body are all identical, just extract that to one function. Custom-build the parameters to the category, then call fetch.
const thatPostFunction = category => {
const method = 'POST'
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }
const body = `USERID=userid&TOKEN=usertoken&CATEGORY=${category}`
return fetch(url, { method, headers, body })
}
const categories = [...category ids...]
const promises = categories.map(c => thatPostFunction(c))
Promise.all(promises)
.then((value) => {
console.log(value)
//json response
})
.catch((err) => {
console.log(err);
});
I would write a function to convert a category id to a Promise, and then write a wrapper function to convert an array of category ids to a Promise resolving to an array of fetch results:
const fetchCategory = (catId) => {
const url = 'http://www.myapiurl.com/thisapi';
const options = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=${catId}`
};
return fetch(url, options)
.then(response => response.json())
}
const fetchCategories = (categories) => Promise.all(categories.map(fetchCategory))
const categories = [1, 2, 3, 4]
fetchCategories(categories).then(categoryResults => {
// here categoryResults is an array of the fetch results for each category.
console.log(categoryResults)
})
<script>
// Faking out fetch for testing
const fetch = (url, opts) => Promise.resolve({
json: () => ({
categoryId: `${opts.body.slice(opts.body.lastIndexOf('=') + 1)}`,
more: 'here'
})
})
</script>
You can just create a function that runs all of them:
const categories = [1,2,3,4];
const postUrls = (items) => {
const promises = []
items.forEach(item => {
const url = 'http://www.myapiurl.com/thisapi';
const options = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=${item}`
};
const prms = fetch(url, options)
.then(response => response.json())
promises.push(prms)
})
return Promise.all(promises)
}
postUrls(categories)
.then(data => console.log('Done!'))
If your API is flexible then you may be able to ask for all 4 categories at the same time. I have seen APIs do it like this:
body: `USERID=userid&TOKEN=usertoken&CATEGORY=1,2,3,4`
And I have seen them do it like this:
body: `USERID=userid&TOKEN=usertoken&CATEGORY=1&CATEGORY=2&CATEGORY=3&CATEGORY=4`
Again, your API would need to be able to enumerate through the categories and return the results in some kind of object or array.

Categories

Resources