使用 axios 和 Redux Saga 调用 API 总是返回 undefined

Posted

技术标签:

【中文标题】使用 axios 和 Redux Saga 调用 API 总是返回 undefined【英文标题】:Call API using axios and Redux Saga always return undefined 【发布时间】:2021-09-20 06:20:48 【问题描述】:

我正在使用axios和redux saga调用api并检查本地输入,但是redux saga总是返回undefined

使用 axios 获取数据的功能

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

动作文件

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 部分

我记录了所有内容,但它返回 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")
    

减速器

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

我如何在主文件上分派

 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>
    );

另外,当我按下时,动作会获取数据,但它在 redux-saga 部分返回未定义,所以用户名总是如此相等,发生了什么??

为什么数据显示在 redux 调试器中,但我在 saga 上看不到,为什么我从 axios 获取的数据返回未定义?

一个简短的 gif 来显示发生了什么

请帮忙,万分感谢

完整代码:https://codesandbox.io/s/github/khanh21011999/Trainning-react-native

【问题讨论】:

【参考方案1】:

首先,您的沙盒无法正常工作,因此请确保它适用于所有人。 第二次尝试在您的代码中像这样使用 async/await,我无法测试它,因为您的沙箱正在崩溃。 export async function requestGetUser() return await axios.get('https://my-json-server.typicode.com/khanh21011999/demo/user');

【讨论】:

对不起,我使用的是 react-native,所以只显示代码,但我不知道如何让它们在 web 上运行 :(( 我试过你的方法,但它显示如下ibb.co/d2BtSQg 当您显式调用get 时,为什么要使用方法和 url 属性传递对象,只需按照我在答案中写的方式尝试 axios。 或者你可以简单地忽略 async/await 并返回 then 和 catch 块。 我想我会选择更简单的方法,我刚刚开始学习 react 和 react native 3 周,没有网络背景,这对我来说太重要了,但感谢你的回答,我很感激那【参考方案2】:

在 axios API 调用中,您需要对成功或失败的响应进行编码,如下所示:

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");
  );

【讨论】:

谢谢你的回答,但是我如何获取function(data)中的数据,我的意思是,如何访问redux-saga文件中的这些数据,我很新,请举个例子 如何获取这些数据? return data 合法吗? 但是当我使用console.log ibb.co/r5xFjF3时显示成功 请帮忙,我被这个问题困扰了好几天:(( 嗨庆。您应该通过在函数内部编码从 .done 函数本身获取数据。您可以在那里执行 console.log(data) 来查看数据(data[0].fieldname、data[1].fieldname...等)。还有其他方法,例如将数据放入全局变量中,这不是一个好方法。

以上是关于使用 axios 和 Redux Saga 调用 API 总是返回 undefined的主要内容,如果未能解决你的问题,请参考以下文章

酶集成测试:axios.get 调用未在 redux-saga 中执行

插入并放入nodeJs + express api时,带有Redux Saga的Axios不发送表单数据

从 redux-saga all 中获取结果,即使有失败

如何使用 Redux-Saga 和 Hooks 调用 API

如何使用 redux-saga 处理异步 API 调用?

如何用 jest 测试 redux saga?