skip to Main Content

I have this problem where component correctly renders state but when I use state in a function, it still holds initial value.

In component render anyway, deviceInfo shows right infos.

const [deviceInfo, setDeviceInfo] = useState({id: null, info: null});
const subscribed = useRef(false);

useEffect(() => {
    sub = subscriber.subscribe(device_info => { // subscriber of rxjs
        if (!subscribed.current) {
            subscribed.current = true;
            if (device_info.id && device_info.info) {
                setDeviceInfo({id: device_info.id, info: device_info.info}); // -> setDeviceInfo useState setter called
                oauth(JSON.parse(JSON.stringify(device_info)));
            }
        }
    });
    if (deviceInfo.info) sub.unsubscribe();
}, []);

when I use state in function it still has initial value { id: null, info: null }

 const requestToken = async (device_auth_res) => {
    ... 
    catch (err) {
        console.error(err.status + ' ' + err.message);
        const type = err.response.body['error'];
        if (type === 'authorization_pending') {
            console.error('Authorization pending...')
        }
        if (type === 'expired_token') {
            console.error(err.response.body.error_description);
            await requestOauth(deviceInfo); // -> deviceInfo is { id: null, info: null }
        }
        if (type === 'auth_request_not_found') {
            console.error(err.response.body.error_description);
            await requestOauth(deviceInfo); // -> deviceInfo is { id: null, info: null }
        }
    }
}

2

Answers


  1. Try as bellow code:

    const [deviceInfo, setDeviceInfo] = useState({ id: null, info: null });
    const subscribed = useRef(false);
    
    useEffect(() => {
      let sub;
      sub = subscriber.subscribe((device_info) => {
        if (!subscribed.current) {
          subscribed.current = true;
          if (device_info.id && device_info.info) {
            setDeviceInfo({ id: device_info.id, info: device_info.info });
            oauth(JSON.parse(JSON.stringify(device_info)));
          }
        }
      });
      if (deviceInfo.info) sub.unsubscribe();
    }, []);
    
    const requestToken = async (device_auth_res) => {
      // Use deviceInfo directly here
      try {
        // ...
    
        const type = err.response.body['error'];
        if (type === 'authorization_pending') {
          console.error('Authorization pending...');
        }
        if (type === 'expired_token') {
          console.error(err.response.body.error_description);
          if (deviceInfo.id && deviceInfo.info) {
            await requestOauth(deviceInfo);
          }
        }
        if (type === 'auth_request_not_found') {
          console.error(err.response.body.error_description);
          if (deviceInfo.id && deviceInfo.info) {
            await requestOauth(deviceInfo);
          }
        }
      } catch (err) {
        console.error(err.status + ' ' + err.message);
      }
    };
    

    you can use the deviceInfo state variable directly within the requestToken function, but make sure to handle potential null values appropriately to avoid errors.

    const [deviceInfo, setDeviceInfo] = useState({ id: null, info: null });
    const subscribed = useRef(false);
    
    useEffect(() => {
      const sub = subscriber.subscribe((device_info) => {
        if (!subscribed.current) {
          subscribed.current = true;
          if (device_info.id && device_info.info) {
            setDeviceInfo({ id: device_info.id, info: device_info.info });
            oauth(JSON.parse(JSON.stringify(device_info)));
          }
        }
      });
      if (deviceInfo.info) sub.unsubscribe();
    }, []);
    
    const requestToken = async (device_auth_res) => {
      try {
        // Use deviceInfo directly here
        console.log('Inside requestToken:', deviceInfo); // Verify if it's updated
    
        // ... your code ...
    
        const type = err.response.body['error'];
        if (type === 'authorization_pending') {
          console.error('Authorization pending...')
        }
        if (type === 'expired_token' || type === 'auth_request_not_found') {
          console.error(err.response.body.error_description);
          if (deviceInfo.id && deviceInfo.info) {
            await requestOauth(deviceInfo);
          }
        }
      } catch (err) {
        console.error(err.status + ' ' + err.message);
      }
    };
    
    Login or Signup to reply.
  2. You can keep a ref that always points to the latest state. This way, even if your function captures an old value of the ref, dereferencing the ref will always give you the current state.

    const deviceInfoRef = useRef(deviceInfo);
    
    useEffect(() => {
        deviceInfoRef.current = deviceInfo;
    }, [deviceInfo]);
    
    const requestToken = async (device_auth_res) => {
        // ... use deviceInfoRef.current instead of deviceInfo
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search