Difference between .then and async/await in React - reactjs

I need to PUT some data to backend, GET a response and use it to setState(), rendering the page syncronously. When using .then the changes made in editPost persist in about half of the time while using async/await seems to work fine(based on experimentation). I'm not sure why this happens since I've been told the two were equivalent:
.then:
onEditSubmit(e){
e.preventDefault()
const newPost = {
id: this.state.id,
title: this.state.titl,
author: this.state.auth,
content: this.state.cont
}
editPost(newPost)
.then(axios.get('/blog')
.then(response => {
this.setState({
posts: response.data,
titl: '',
auth: '',
cont: ''
})
}))
}
async/await:
async onEditSubmit(e){
e.preventDefault()
const newPost = {
id: this.state.id,
title: this.state.titl,
author: this.state.auth,
content: this.state.cont
}
await editPost(newPost)
var response = await axios.get('/blog')
await this.setState({
posts: response.data,
titl: '',
auth: '',
cont: ''
})
}
editPost:
export const editPost = editPost => {
return axios.put(`/blog/write/${editPost.id}`, {
title : editPost.title,
author : editPost.author,
content : editPost.content
})
}
Note: I'm not sure if the fact that setState() being async has to do with this.

You should have a callback function in the first promise:
onEditSubmit(e){
e.preventDefault()
const newPost = {
id: this.state.id,
title: this.state.titl,
author: this.state.auth,
content: this.state.cont
}
editPost(newPost)
.then(() => {
axios.get('/blog')
.then(response => {
this.setState({
posts: response.data,
titl: '',
auth: '',
cont: ''
})
})
})
}

Related

React, trying to use setState only once

Is there any other good way to use setState() only once?
onSearchSubmit = async input => {
const response = await weather.get('/weather', {
params: {
q: this.state.city || input,
},
});
this.setState({ weather: response.data, input: '', city: '' });
};
And then in render function:
this.state.city ? this.onSearchSubmit() : this.onSearchSubmit

formik form reset on action dispatch

is there any possible ways to reset the form right after I dispatch the action ?
something like:
const formik = useFormik({
onSubmit: (values, {resetForm}) => {
dispatch(action.register(values)) //some action creator with axios.post request
if (isRegistred) { resetForm() } //isRegistred - value from Selector which changes on dispatch to true
}
})
const register = (user) => (dispatch) => {
return axios
.post(`${API_URL}/user/create/`, {
first_name: user.firstName,
second_name: user.secondName,
date_birth: user.dateBirth,
phone_number: user.phoneNumber,
gender: user.gender,
email: user.email,
city: user.city,
username: user.username,
password1: user.password1,
password2: user.password2
})
.then((response) => {
dispatch({ type: '#USER/register-success', isRegistred: response.data?.success })
})
.catch((error) => {
dispatch({ type: '#USER/register-error', error: error?.response?.data?.errors })
})
}
export const action = { register }
I know, it's kinda silly, because it's changing value right after.
Maybe there any other approaches ?
if someone intrested, i just pass the resetForm from onSubmit formik to action creator.
const formik = useFormik({
initialValues,
validationSchema,
onSubmit: (values, { resetForm }) => {
dispatch(userActions.register(values, { resetForm }))
},
validateOnChange: false,
validateOnBlur: true
})
const register = (user, { resetForm }) => (dispatch) => {
return axios
.post(`${API_URL}/user/create/`, {
first_name: user.firstName,
second_name: user.secondName,
date_birth: user.dateBirth,
phone_number: user.phoneNumber,
gender: user.gender,
email: user.email,
city: user.city,
username: user.username,
password1: user.password1,
password2: user.password2
})
.then((response) => {
dispatch({ type: '#USER/register-request' })
if (response.data?.success) {
dispatch({ type: '#USER/register-success', isRegistred: response.data?.success })
resetForm()
}
})
.catch((error) => {
dispatch({ type: '#USER/register-error', error: error?.response?.data?.errors })
})
}

This.props doesn't load data from react/redux

I have the following method:
const getAgentData = () => {
axios.get('http://localhost:3000/api/agent', {
headers: {
'Content-Type': 'application/json'
}
})
.then(async res => {
const dbData = res.data.data;
let dataForTable = dbData.map( el => {
let obj = {};
obj._id = el._id;
obj.name = el.name;
obj.phone = el.phone;
if(el.name) {obj.email = el.email}
return obj;
})
await dispatch({ type: 'ADD_PHOTOGRAPHERS', dataForTable });
})
.then(() => {
setLoading(false)
})
.catch((error) => {
console.error(error)
})
}
I update the redux state with this line: await dispatch({ type: 'ADD_PHOTOGRAPHERS', dataForTable });
in a child component I run this:
componentDidMount() {
console.log(this.props.photographers)
}
In the original state this.props.photographers = [];
this is what is logged to the console, it never logs the udpated redux state. From my understading redux should automatically update and it should console.log the udpated state. Any idea what I'm doing wrong?
I also tried logging data with the props being here but it's also an empty array:
class DataTableComponent extends Component {
constructor(props) {
super(props)
this.state = {
data: this.props.photographers,
loading: false,
name: '',
phone: '',
email: '',
}
}
...
My redux map to props in the child component I'm describing is:
function mapStateToProps(state) {
return {
photographers: state.Customizer.photographers
}
}
export default connect(mapStateToProps)(DataTableComponent);
Check if await dispatch({ type: 'ADD_PHOTOGRAPHERS', dataForTable });, seems that you are not sending the payload correctly.
You can log or debug how this action payload data is coming to its reducer.

Add array of images to Firebase storage and realtime database using React JS

I am trying to push an array of local images to Firebase store and my database. The images are being outputted in my database json scheme but nothing is showing up in storage and keep receveing the following errors below. Any thoughts?
Error:
Database JSON scheme:
{
"users" : {
"XhLxS1KUS8UyHjsuHYrEuyipQX53" : {
"Email" : "ssssss#gmail.com",
"code" : "bob",
"image1" : {
"id" : "223d7f60-331b-11e9-b680-6b36b34d4cc6",
"url" : "holder1.png"
},
"image2" : {
"id" : "223da670-331b-11e9-b680-6b36b34d4cc6",
"url" : "holder2.png"
},
"image3" : {
"id" : "223da671-331b-11e9-b680-6b36b34d4cc6",
"url" : "holder3.png"
},
"location" : "fl"
}
}
}
React JS:
const images = [
{
id: uuid(),
url: `holder1.png`
},
{
id: uuid(),
url: `holder2.png`
},
{
id: uuid(),
url: `holder3.png`
}
];
class Register extends Component {
state = {
email: '',
password: '',
code: 'bob',
location: 'fl',
image: null,
url: '',
error: null,
arr: images,
};
handleInputChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
handleChange = e => {
if (e.target.files[0]) {
const image = this.state.arr;
this.setState(() => ({ image }));
console.log(image)
}
}
handleSubmit = (event) => {
event.preventDefault();
const { email, password, image, url } = this.state;
const storageRef = storage.ref(`images/`);
this.state.image.map((file, index) => {
storageRef
.child(`${file.url}`)
.getDownloadURL().then(url => {
this.setState({ url }); <---Should I set state?
})
});
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((user) => {
firebase
.database()
.ref('users/' + user.user.uid)
.set({
Email: user.user.email,
code: this.state.code,
location: this.state.location,
image1: images[0],
image2: images[1],
image3: images[2]
})
//console.log(this.state.url)
this.props.history.push('/');
})
.catch((error) => {
this.setState({ error: error });
});
};
....
This works for a single image to storage:
React JS:
class Register extends Component {
state = {
email: '',
password: '',
code: 'bob',
location: 'fl',
image: null,
url: '',
error: null,
};
handleInputChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
handleChange = e => {
if (e.target.files[0]) {
const image = e.target.files[0];
this.setState(() => ({image}));
}
}
handleSubmit = (event) => {
event.preventDefault();
const { email, password, image, url } = this.state;
const uploadTask = storage.ref(`images/${image.name}`).put(image);
uploadTask.on('state_changed', () => {
storage.ref('images').child(image.name).getDownloadURL().then(url => {
console.log(url);
this.setState({url});
})
});
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((user) => {
firebase
.database()
.ref('users/' + user.user.uid)
.set({
Email: user.user.email,
code: this.state.code,
location: this.state.location,
image: this.state.url
})
this.props.history.push('/');
})
.catch((error) => {
this.setState({ error: error });
});
};
...
As I commented on your previous question:
You need to write the URL to the database from within the callback to getDownloadUrl(). So where you now call this.setState({url});, call something like firebase.database().ref('users/' + user.user.uid + '/image').set(url); too.
In addition, as far as I can see from the documentation, there are three callbacks for UploadTask.on('state_changed' and the third is called when the upload is completed.
So:
uploadTask.on('state_changed', function(snapshot) {
// handle progress messages here
},(error) => {
// handle errors here
},() => {
storage.ref('images').child(image.name).getDownloadURL().then(url => {
console.log(url);
this.setState({url});
firebase.database().ref('users/' + user.user.uid + '/image').set(url);
})
});

this not working in async function in React component

In my React component this.login() isn't executing. I believe this is because an await function changes the context of this, but I'm not sure how to fix it.
await this.props
.SignupUser({
variables: {
email: this.state.email,
password: this.state.password,
name: this.state.name,
},
})
.then(() => {
this.login();
})
.catch(error => {
this.setState({ wait: false });
const errorMessage = error.graphQLErrors[0].functionError;
this.setState({ error: errorMessage });
});
Remove await keyword, It should work.
Alternatively, we need to implement in a different way
The function must add async keyword in the function declaration for below code
await this.props
.SignupUser({
variables: {
email: this.state.email,
password: this.state.password,
name: this.state.name,
},
})
.then(() => {
this.login();
})
.catch(error => {
this.setState({ wait: false });
const errorMessage = error.graphQLErrors[0].functionError;
this.setState({ error: errorMessage });
});
(or)
try {
const user = await this.props
.SignupUser({
variables: {
email: this.state.email,
password: this.state.password,
name: this.state.name,
},
});
this.login();
} catch (e) {
this.setState({ wait: false });
const errorMessage = error.graphQLErrors[0].functionError;
this.setState({ error: errorMessage });
}

Resources