I am facing a problem with getting the updated state
data in a functional component. I have seen threads on SO where it is recommended to switch to a Class component where states can be managed better without the use of hooks but I feel like same should be possible with hooks in a functional component.
My code is as follows
function HomePage(){
const [selected, setSelected] = useState({});
const [locationOptions, setLocationOptions] = useState([
{label: 'Location 1', value: 'location-1'},
{label: 'Location 2', value: 'location-2'},
{label: 'Location 3', value: 'location-3'},
]);
// Getting the data from the servers and updating the state
// works fine in the render, the data gets updated
const { data: locationData, refetch: locationDataRefetch } = useAppQuery({
url: "/api/get-locations",
reactQueryOptions: {
onSuccess: async ( e ) => {
if ( e.data ) {
setLocationOptions( e.data );
} else {
// handle errors
}
},
},
});
const seeUpdatedLocations = () => {
// This is where the problem is, even after the state is updated after getting
// the data from the API, this still logs the initial value of locationOptions
console.log( locationOptions );
}
const handleSelectChange = useCallback((value) => {
// This is where the problem is, even after the state is updated after getting
// the data from the API, this still logs the initial value of locationOptions
// value can be 'location-1', and I use lodash to get the right object from locationOptions
let selectedLocationObj = _.find( locationOptions, ( o ) => o.value == value );
console.log( selectedLocationObj ); // Doesn't work as the locationOptions doesn't contain the real values received from API
}, []);
return (
<Select
label="Location"
options={locationOptions}
onChange={ handleSelectChange }
value={ selected.value }
labelHidden={true}
/>
);
}
CodePudding user response:
As stated in the documentation of useCallback
(emphasis mine):
Pass an inline callback and an array of dependencies.
useCallback
will return a memoized version of the callback that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g.shouldComponentUpdate
).
The dependency array of your useCallback
is empty, this means that the function is never updated, so you always get the initial values. Adding locationOptions
as a dependency should solve your problem.
You should also ask yourself if this useCallback
is necessary. Here is a great article about that.