Home > other >  Getting the updated state data in a functional component
Getting the updated state data in a functional component

Time:08-14

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.

  • Related