reactjsreact-nativereduxreact-redux

React Native useSelector not updating state in Container


I'm working on a React Native app, and I'm having some issues regarding conditional rendering based on the Redux state, which I fetch using useSelector.

I have tried with and without the useEffect below (so with returning the component directly instead of setting a state), but the variables returned from useSelector do not seem to change when the state is updated. Since the states are loading at first, I end up in the latest else if, and get stuck there. I have to then refresh the app to get the actual values and get to the desired screen

const ContainerA = ({ navigation }) => {

    const {
        loginSuccess,
        loginLoading,
        accountType,
        permissionsSuccess,
        permissionsLoading,
    } = useSelector((state) => state.accountInfo);

    const [toRender, setToRender] = useState(null);

    useEffect(() => {

        if (loginSuccess) {
            if (loginSuccess.success === 1 && accountType === 3) {
                console.log('[Container] case 1');

                setToRender(<PageA navigation={navigation} />);
                // return <PageA navigation={navigation} />;
                // return;
            } else if (
                (loginSuccess.success === 1 &&
                (accountType === 1 || accountType === 2)) || (loginSuccess.success === 0)
            ) {
                console.log('[Container] case 2');
                navigation.navigate(SCREENS.CONTROL_PANEL);
            }
        } else if (loginLoading || permissionsLoading) {
            console.log('[Container] case 4');
            setToRender(<LoadingPage />);
            // return <LoadingPage />;
            // return;
        }
    }, [
        loginSucess,
        loginLoading,
        accountType,
        navigation,
        permissionSuccess,
        permissionsLoading,
    ]);

    return toRender;
};

export default ContainerA;

Redux reducer:

case 'loginInit':
            return updateState(state, {
                loginLoading: true,
                loginSuccess: null,
                loginFail: null,
            });
        case 'loginSuccess':
            return updateState(state, {
                loginLoading: false,
                loginSuccess: action.success,
            });
        case 'loginFail':
            return updateState(state, {
                loginLoading: false,
                loginFail: action.error,
            });
        case 'permissionsInit':
            return updateState(state, {
                permissionsLoading: true,
                accountType: null,
                permissionsSuccess: null,
                permissionsFail: null,
            });
        case 'permissionsSuccess':
            return updateState(state, {
                permissionsLoading: false,
                permissionsSuccess: action.success,
                accountType: action.success.success
                    ? action.success.success
                    : action.success.errors,
            });
        case 'permissionsFail':
            return updateState(state, {
                permissionsLoading: false,
                permissionsFail: action.error,
            });

updateState function:

export const updateState = (state, updatedProps) => ({
    ...state,
    ...updatedProps,
});

Solution

  • Seems like I was executing the functions that do the checks in a place where I shouldn't get any successful response. I fixed it by calling those functions in the Navigator where I was sure to have the token, since those calls required it (and which were not doing the actual API call without it). The code remaining in ContainerA is:

    const {
            firstLoginSuccess,
            firstLoginLoading,
            accountType,
            permissionsSuccess,
            permissionsLoading,
        } = useSelector((state) => state.accountInfo);
    
        if (firstLoginSuccess) {
            if (firstLoginSuccess.success === 1 && accountType === 3) {
                return <FirstTimeLoginPage navigation={navigation} />;
            } else if (
                (firstLoginSuccess.success === 1 &&
                    (accountType === 1 || accountType === 2)) ||
                firstLoginSuccess.success === 0
            ) {
                navigation.navigate(SCREENS.CONTROL_PANEL);
            }
        } else if (firstLoginLoading || permissionsLoading) {
            console.log('[FirstTimeLoginContainer] case 4');
        }
    
        return <LoadingPage />;