Call API using axios and Redux Saga always return undefined

I'm using axios and redux saga to call api and check with local input, but redux saga always return undefined

Function to get data using axios

export function requestGetUser() {
  return axios({
    method: 'get',
    url: 'https://my-json-server.typicode.com/khanh21011999/demo/user',
  });
}

Action file

export const getUser = () => ({
    type: actionList.GET_USER,
});
export const setUser = (user) => ({
    type: actionList.SET_USER,
    user,
});
export const GetUserInfo = (user, password) => {
    return{
        type: actionList.GET_USER_INFO,
        data: {user, password},
    }
};
export const LoginSuccess = (data) => {
    return {
        type: actionList.LOGIN_SUCCESS,
        data,
    };
};

export const LoginFailed = (data) => {
    return {
        type: actionList.LOGIN_FAIL,
        data,
    };
};

export const Logout = (data) => {
    return {
        type: actionList.LOG_OUT,
        data
    };
};

Redux-saga part

I log everything but it return undefined

export function* LoginsSagaFunc() {
    yield takeLatest('GET_USER_INFO', loginSaga)

}
function* SaveToAsyncStorage(data) {
    try {
        AsyncStorage.setItem(
            'data',
            JSON.stringify({
                username: data.username,
                password: data.password
            }))
    } catch (e) {
        console.log('error save to Storage');
    }
}

function* loginSaga(action) {

    console.log('Saga is working')
    const getJson = yield call(requestGetUser)
    const getJsonData = JSON.parse(JSON.stringify(getJson))

    const getJsonUsername = String(getJsonData.username)
    console.log('JsonUsername '+getJsonUsername)
    console.log("local data " + action.data.username)
    console.log('getJsonData '+getJsonData)
    console.log('GetJson '+getJson)
    

    const getJsonPassword = String(getJsonData.password)

    if (String(action.data.username) === getJsonUsername) {
        if (String(action.data.password) === getJsonPassword) {
            console.log('saga login success')
            yield put({type: 'LOGIN_SUCCESS'})
            SaveToAsyncStorage(action.data)
        }
        else {
            console.log('saga password fail')
        }
    }
    else {
        console.log("saga user fail")
    }
}

The reducer

const initStateAuth={
        isAuth:false,
        isLogIn:false
    }
    const AuthReducer =(state=initStateAuth,action)=>{
        switch (action.type) {
        case actionList.LOGIN_SUCCESS:
          {
            console.log('action : LOG IN SUCCESS');
            return {
                    
              isAuth: true,
                        isLogIn: true,
            };
          }
            case actionList.GET_USER_INFO:
                {
                    return initStateAuth
                }
        case actionList.LOGIN_FAIL:
          {
           
            return initStateAuth
          }
        case actionList.LOG_OUT:
          {
            return initStateAuth
          }
        default:
          return state;
      }
    
    
    }
    export default AuthReducer

How i dispatch on the main file

 function LoginScreen({navigation}) {
    // set timeout ID for setTimeOut()
    const timeIdRef = React.useRef(null);
    const dispatch = useDispatch();
    const [username, getUsername] = useState('');
    const [password, getPassword] = useState('')

    // handleInput = (e) => {
    //  getUserInfo(e.target.value);
    // };

    // mock user from fake api
    useEffect(() => {
        // dispatch(getUser());
        
    }, [dispatch]);
    dispatch(GetUserInfo(username, password));
    //  const handlegetdata= ({user,password})=>{
    // dispatch(GetUserInfo(user,password))
    // // }

    // console.log(handleGetdata.user)


    const user = useSelector((state) => {
        return state.User.user;
    });
    // console.log('user' + username)
    //  console.log('userJSon'+user.username)
    useEffect(() => {
        return () => {
            if (timeIdRef.current) {
                // make sure this is always cleared in case clearTo is never called
                clearTimeout(timeIdRef.current);
            }
        };
    }, [timeIdRef]);
    // console.log();

    const Login = useSelector((state) => {
        return state.LoginAction.loginStatus;
    });
    // console.log(Login)
    //   const initModal = false;
    // eslint-disable-next-line require-jsdoc
    function handleLogin() {
        dispatch({type: 'changeLogin'});
    }
    function handlDefault() {
        dispatch({type: 'getDefault'});
    }

    // not show??
    // console.log(username);
    // console.log('Login ' + Login)
    //   const [show, doShow] = useState(initModal);

    // const [visible, UpdateView] = useState(false)

    // Show modal dialog
    //   function ChangeModalValue() {
    //     console.log(show);
    //     doShow(!show);
    //   }
    // setTimer after Model Appear

    function SetTimer() {
        handleLogin();
        if (timeIdRef.current) {
            // clear any previous timeIdRef to avoid multiple button click activate multiple setTimeout
            clearTimeout(timeIdRef.current);
        }
        const timeID = setTimeout(() => {
            navigation.navigate('Home');
        }, 3000);
        timeIdRef.current = timeID;
    }

    function clearTO() {
        clearTimeout(timeIdRef.current);
        timeIdRef.current = null;
        handlDefault();
    }

    // make text black when check complete
    function getTextStyle(isValid) {
        if (isValid) {
            return {
                color: 'black',
            };
        }

        return {
            color: 'grey',
        };
    }
    //   function getLoginText() {
    //     return <CirclesLoader />;
    //   }
    // function hideText(visible){
    //     if(isDisabler)

    // }
    const loginValidationSchema = Yup.object().shape({
        email: Yup.string().email('Please enter valid email').required('Email Address is Required'),
        password: Yup.string()
            .min(8, ({min}) => `Password must be at least ${min} characters`)
            .required('Password is required'),
    });
    return (
        <View style={styles.ViewStyle}>
            <Text style={{fontSize: 40}}>Login To System</Text>

            <Formik
                validateOnMount
                validationSchema={loginValidationSchema}
                initialValues={{email: '', password: ''}}
                onSubmit={value => {
                    getUsername(value.email)
                    getPassword(value.password)
                    SetTimer()
                }}
            // () => navigation.navigate('Login')
            >
                {({handleChange, handleBlur, handleSubmit, values, errors, touched, isValid}) => (
                    <View>
                        <TextInput
                            name="email"
                            placeholder="Email Address"
                            style={styles.TextInputForm}
                            onChangeText={handleChange('email')}
                            onBlur={handleBlur('email')}
                            value={values.email}
                            keyboardType="email-address"
                        />
                        {errors.email && touched.email && <Text style={styles.errorText}>{errors.email}</Text>}
                        <TextInput
                            name="password"
                            placeholder="Password"
                            onChangeText={handleChange('password')}
                            onBlur={handleBlur('password')}
                            value={values.password}
                            secureTextEntry
                            style={styles.TextInputForm}
                        />
                        {errors.password && touched.password && (
                            <Text style={styles.errorText}>{errors.password}</Text>
                        )}

                        <TouchableOpacity
                            onPress={handleSubmit}
                            style={styles.ButtonLogin}
                            disabled={!isValid || values.email === ''}>
                            {/* <CirclesLoader size={20} dotRadius={7} /> */}
                            <Text style={getTextStyle(isValid)}>Login</Text>
                        </TouchableOpacity>
                        <View>
                            <Modal transparent visible={Login}>
                                <View
                                    style={{
                                        backgroundColor: '#000000',
                                        flex: 1,
                                        justifyContent: 'center',
                                        alignContent: 'center',
                                    }}>
                                    <View style={styles.ModalStyle}>
                                        <CirclesLoader />
                                        <TextLoader
                                            textStyle={{
                                                fontSize: 25,
                                                marginTop: 20,
                                            }}
                                            text="Logging you in"
                                        />
                                        <TouchableOpacity onPress={clearTO} style={styles.ButtonBack}>
                                            <Text>Go back</Text>
                                        </TouchableOpacity>
                                    </View>
                                </View>
                            </Modal>
                        </View>
                    </View>
                )}
            </Formik>
        </View>
    );
}

Also, the action get the data when i press, BUT it return undefined in redux-saga part, so username always so equal, what happened??

Why data show in redux debugger but i can't see it on saga, and why data i fetch from axios return undefinded?

a short gif to show what happened enter image description here

enter image description here Please help, thank you a lot

FULL CODE : https://codesandbox.io/s/github/khanh21011999/Trainning-react-native

Upvotes: 0

Views: 1762

Answers (2)

Piyush Rana
Piyush Rana

Reputation: 667

First of all your sandbox is not working so make sure it works for all. Second try using async/await like this in your code, I'm not able to test it because your sandbox is crashing. export async function requestGetUser() { return await axios.get('https://my-json-server.typicode.com/khanh21011999/demo/user'); }

Upvotes: 0

Ezani
Ezani

Reputation: 557

In the axios API call, you need to code for a successful or a failed response as follows:

export function requestGetUser() {
  return axios({
    method: 'get',
    url: 'https://my-json-server.typicode.com/khanh21011999/demo/user',
  })
.done (function(data) {
    //Get your data here upon successful fetch
  })
.fail (function() {
    console.log("Failed to fetch data");
  })
.always (function() {
    console.log("This function always executes whether success or fail");
  });
}

Upvotes: 1

Related Questions