microsoft / react-native-code-push

React Native module for CodePush
http://appcenter.ms
Other
8.98k stars 1.47k forks source link

How to update a state in codePush.sync() callbacks #2531

Closed cashbackdev closed 9 months ago

cashbackdev commented 1 year ago

Hi I have problems setting states and rerendering my component during the download of the update.

Steps to Reproduce

  1. Here is a simplified version of my component :

    
    import React, { useEffect, useState, useContext } from 'react'
    import { Context } from '../components/MyContext'
    import codePush from "react-native-code-push";
    import ProgressBar from '../components/ProgressBar';
    export default function SplashScreen() {
    const context = useContext(Context);
    const [progressBarCurrent, setProgressBarCurrent] = useState(0);
    const [progressBarTotal, setProgressBarTotal] = useState(0);
    const otaDownloadProgressHandler = async (status) => {
        if (!status) {
            return
        };
        if (progressBarTotal == 0) {
            setProgressBarTotal(status.totalBytes);
        }
        console.log('set state called !')
        setProgressBarCurrent(status.receivedBytes);
    }
    const postSplash = async () => {
        let updateCheck = false;
        try {
            updateCheck = await codePush.checkForUpdate();
        } catch (e) { }
        if (updateCheck) {
            codePush.disallowRestart();
            setShowProgressBar(true);
            await codePush.sync({
                updateDialog: null,
                installMode: codePush.InstallMode.IMMEDIATE
            }, otaStatusChangeHandler, otaDownloadProgressHandler);
        }
    }
    useEffect(() => {
        (async () => {
            if (context.isReady) {
                await postSplash();
                setWorkIsDone(true);
            }
        })();
    }, [context])
    
    console.log("RENDER")
    
    return (
        <ProgressBar currentState={progressBarCurrent} total={progressBarTotal} />
    )

}


### Expected Behavior
When I run the update, I can't see the `console.log` 'RENDER' in my console which means that my component re-rendered after the setState

### Actual Behavior
I can see in the console this log : 'set state called !' which is called just before the setState function, but not the 'RENDER' one...

### Environment

* react-native-code-push version: "^7.1.0"
* react-native version:"0.71.1"
* iOS/Android/Windows version: iOS 16.2
* Does this reproduce on a simulator, or only on a physical device? both

Thanks a lot for your help !
microsoft-github-policy-service[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had any activity for 60 days. It will be closed if no further activity occurs within 15 days of this comment.

microsoft-github-policy-service[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had any activity for 60 days. It will be closed if no further activity occurs within 15 days of this comment.

alihamza1729 commented 1 year ago

Facing same issue

react-native-code-push version: "^8.1.0"

react-native version:"0.71.1"

alihamza1729 commented 12 months ago

Hi I have problems setting states and rerendering my component during the download of the update.

Steps to Reproduce

Here is a simplified version of my component :

import React, { useEffect, useState, useContext } from 'react'
import { Context } from '../components/MyContext'
import codePush from "react-native-code-push";
import ProgressBar from '../components/ProgressBar';
export default function SplashScreen() {
    const context = useContext(Context);
    const [progressBarCurrent, setProgressBarCurrent] = useState(0);
    const [progressBarTotal, setProgressBarTotal] = useState(0);
    const otaDownloadProgressHandler = async (status) => {
        if (!status) {
            return
        };
        if (progressBarTotal == 0) {
            setProgressBarTotal(status.totalBytes);
        }
        console.log('set state called !')
        setProgressBarCurrent(status.receivedBytes);
    }
    const postSplash = async () => {
        let updateCheck = false;
        try {
            updateCheck = await codePush.checkForUpdate();
        } catch (e) { }
        if (updateCheck) {
            codePush.disallowRestart();
            setShowProgressBar(true);
            await codePush.sync({
                updateDialog: null,
                installMode: codePush.InstallMode.IMMEDIATE
            }, otaStatusChangeHandler, otaDownloadProgressHandler);
        }
    }
    useEffect(() => {
        (async () => {
            if (context.isReady) {
                await postSplash();
                setWorkIsDone(true);
            }
        })();
    }, [context])

    console.log("RENDER")

    return (
        <ProgressBar currentState={progressBarCurrent} total={progressBarTotal} />
    )

}

Expected Behavior

When I run the update, I can't see the console.log 'RENDER' in my console which means that my component re-rendered after the setState

Actual Behavior

I can see in the console this log : 'set state called !' which is called just before the setState function, but not the 'RENDER' one...

Environment

  • react-native-code-push version: "^7.1.0"
  • react-native version:"0.71.1"
  • iOS/Android/Windows version: iOS 16.2
  • Does this reproduce on a simulator, or only on a physical device? both

Thanks a lot for your help !

Did you found any solution?

DmitriyKirakosyan commented 11 months ago

@cashbackdev , @alihamza1729 Could you create a minimal demo application reproducing this problem?

devic021 commented 11 months ago

Same problem here:

useEffect(() => { const codePushStatusDidChange = (syncStatus: CodePush.SyncStatus) => { console.log('CodePush sync status: ', syncStatus); if (syncStatus === CodePush.SyncStatus.DOWNLOADING_PACKAGE) { setIsUpdating(true); } else if (syncStatus === CodePush.SyncStatus.INSTALLING_UPDATE) { setIsUpdating(true); } else if ( syncStatus === CodePush.SyncStatus.UPDATE_INSTALLED || syncStatus === CodePush.SyncStatus.UNKNOWN_ERROR ) { setIsUpdating(false); } };

const codePushDownloadDidProgress = (progress: any) => {
  console.log(
    progress.receivedBytes + ' of ' + progress.totalBytes + ' received.',
  );
};

CodePush.sync(
  codePushOptions,
  codePushStatusDidChange,
  codePushDownloadDidProgress,
);

}, []);

I'm not able to set loader on download or update install at all.

react-native-code-push version: "^8.1.0" react-native version:"0.72.4"

alihamza1729 commented 11 months ago

Same problem here:

useEffect(() => { const codePushStatusDidChange = (syncStatus: CodePush.SyncStatus) => { console.log('CodePush sync status: ', syncStatus); if (syncStatus === CodePush.SyncStatus.DOWNLOADING_PACKAGE) { setIsUpdating(true); } else if (syncStatus === CodePush.SyncStatus.INSTALLING_UPDATE) { setIsUpdating(true); } else if ( syncStatus === CodePush.SyncStatus.UPDATE_INSTALLED || syncStatus === CodePush.SyncStatus.UNKNOWN_ERROR ) { setIsUpdating(false); } };

const codePushDownloadDidProgress = (progress: any) => {
  console.log(
    progress.receivedBytes + ' of ' + progress.totalBytes + ' received.',
  );
};

CodePush.sync(
  codePushOptions,
  codePushStatusDidChange,
  codePushDownloadDidProgress,
);

}, []);

I'm not able to set loader on download or update install at all.

react-native-code-push version: "^8.1.0" react-native version:"0.72.4"

I have faced this issue but later on I got to know either I should user codePush.sync or HOD codePush(App.js). To set loader and check progress, remove HOD and use only codePush.sync()

microsoft-github-policy-service[bot] commented 9 months ago

This issue will now be closed because it hasn't had any activity for 15 days after stale. Please feel free to open a new issue if you still have a question/issue or suggestion.