Home > Blockchain >  How do I change state asynchronously
How do I change state asynchronously

Time:01-21

I'm trying to get the coords of the user and once done I'm trying to use "useState" to make that position global but for some reason it's always returning undefined the first time it's ran even though I'm using a promise.

    const [globalPosition, setGlobalPosition] = useState<any>(undefined);

useEffect(() => {
    const getLocation = new Promise<void>((resolve, reject) => {
        navigator.geolocation.getCurrentPosition(success, error, {
            enableHighAccuracy: true,
        });
        function success(position: any) {
            setGlobalPosition(position);
            resolve();
        }
        function error(err: any) {
            console.log(err);
            reject();
        }
    });
    getLocation.then(() => {
        console.log(globalPosition);
    });
}, []);

CodePudding user response:

The problem with your code is that the setGlobalPosition function is being called asynchronously, so the globalPosition state variable is not being updated in time for it to be logged in the then block of the promise.

One way to fix this is to move the console.log(globalPosition) inside the success function, after calling setGlobalPosition(position). This will ensure that the globalPosition is logged only after it has been updated.

useEffect(() => {
const getLocation = new Promise<void>((resolve, reject) => {
    navigator.geolocation.getCurrentPosition(success, error, {
        enableHighAccuracy: true,
    });
    function success(position: any) {
        setGlobalPosition(position);
        console.log(globalPosition);
        resolve();
    }
    function error(err: any) {
        console.log(err);
        reject();
    }
});

}, []);

CodePudding user response:

The first render will always be undefined because that's what you defined as the initial value.

const [globalPosition, setGlobalPosition] = useState<any>(undefined);
//                                                        ^^^^^^^^^

When a state setting function is called, such as inside your useEffect, the component will rerender.

If you don't want to continue rendering while undefined, after that useEffect add one of these options (or your own loading state):

if (globalPosition == undefined) return null;
if (globalPosition == undefined) return <div>Loading...</div>;

Also because of how React state and const work, getLocation.then's globalPosition will not be the new version of the variable after you change it since it's storing a copy/reference to the original state at the beginning of that render.

  • Related