问题
I have an interesting problem in my code and I am not sure why it happens. Hopefully someone can explain. Basically, I am using "setValues" for my hooks before I call the "dispatch"-method. However, it seems like dispatch is still triggered before the values in the hooks are updated. Even though to me it seems like it should be the other way around. Why does this happen? Here is some of the code:
import React, { useState } from 'react';
import Grid from '@material-ui/core/Grid';
import InputField from 'shared/components/form/Inputfield';
import DatePicker from 'shared/components/pickers/DatePicker';
import InfoButton from 'shared/components/buttons/InfoButton';
import CustomButton from 'shared/components/buttons/CustomButton';
import TextArea from 'shared/components/form/TextArea';
import { connect } from 'react-redux';
export function ProjectDetails(props) {
const [values, setValues] = React.useState({
full_project_name: ' ',
short_name: ' ',
associated_projects: ' ',
short_description: ' ',
});
const handleInputFieldChange = field_name => event => {
setValues({ ...values, [field_name]: event.target.value });
//why does dispatch happen before values are updated?
props.dispatch({ type: 'PLEASE_WORK', payload: values });
};
console.log('Project values', values);
return (
<>
<h1>Project Details</h1>
<Grid container spacing={1}>
<Grid item xs={12}>
<h3>Full project name *</h3>
</Grid>
<Grid item xs={12}>
<InputField
handler={handleInputFieldChange('full_project_name')}
placeHolderText="Please type the last letter two times"
/>
</Grid>
<Grid item xs={12}>
<h3>Short name (Acronym)</h3>
</Grid>
<Grid item xs={12}>
<InputField handler={handleInputFieldChange('short_name')} />
</Grid>
</Grid>
</>
);
}
function mapStateToProps(state) {
return {
full_project_name: state.projectReducer.full_project_name,
short_name: state.projectReducer.short_name,
};
}
export default connect(mapStateToProps)(ProjectDetails);
回答1:
React setState is asynchronous, this means that when you call setValues to set the state of values it initiates the process but proceeds to execute the next line before necessarily finishing.
You could call dispatch with the exact value as well to ensure it is correct, like props.dispatch({ type: 'PLEASE_WORK', payload: { ...values, [field_name]: event.target.value } });
回答2:
To further add to Maddo's answer, if you think about it, the React Component, in the end, is actually just a regular function that got called at some point:
export function ProjectDetails(props)
So, when the function is called, the variables inside its scope simply hold the value of what was there when the function was called (let's say, on that run of the render):
const [ values, setValues ] = useState(...); // <-- values is const
Essentially, values won't change in the current "run" and only after the next time the component is rendered. Notice it's even declared as const to make sure we can't touch it ;)
What is the result of console.log(values) here?
If in doubt, console.log can be your friend (alert is even more fun to use!)
const handleInputFieldChange = field_name => event => {
setValues({ ...values, [field_name]: event.target.value });
// -> what is the result of values here ? (hint: values is const)
console.log('values is:', JSON.stringify(values));
props.dispatch({ type: 'PLEASE_WORK', payload: values });
};
The way I prefer to do it, is to simply put everything in a new variable to assure we are using that:
const handleInputFieldChange = field_name => event => {
const newValues = { ...values, [field_name]: event.target.value };
setValues(newValues);
props.dispatch({ type: 'PLEASE_WORK', payload: newValues });
};
This makes skimming through the code easier to understand: you created a newValues, set it in the state, and then dispatched an action with it.
Hope this makes sense!
回答3:
UseEffect can also help you to resolve the problem with async call "setValues".
You can set the "values" as dependencies to useEffect, then just simply trigger dispatch in useEffect.
I create here a DEMO:
Please have a look at the console logs.
来源:https://stackoverflow.com/questions/58150089/why-does-redux-dispatch-happen-before-hook-values-are-updated