【问题标题】:TypeError: dispatch(...).then is not a functionTypeError: dispatch(...).then 不是函数
【发布时间】:2021-11-03 05:43:10
【问题描述】:

处理我的 API 登录,在邮递员中发送请求时如下所示:

{
    "token": {
        "id": 5896,
        "user_id": 125188,
        "api_token": "xxx4444444sss4",
        "expires_on": "2021-12-29 08:21:09",
        "created_at": "2021-08-04 03:34:25",
        "updated_at": "2021-10-29 03:21:09"
    },
    "user": {
        "id": 15088,
        "username": "cath.smith",
        "firstname": "Cath",
        "lastname": "Smith",
        "email": "cath.smith@gmail.com",
        "created_at": "2021-08-04 03:34:25",
        "updated_at": "2021-10-29 03:21:09",
        "deleted_at": null
    },
    "code": 200
}

在我的authApi.js 上看起来像这样:

export const loginUserApi = authData => {
  const {email, password} = authData;

  return axios.post(`${API_URL}/v1/token`, {
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${API_KEY}`,
    },
    body: JSON.stringify({
      email,
      password,
    }),
  });
};

我在我的authAction.js 上这样管理:

export const loginUserStart = authData => ({
  type: type.LOGIN_USER_START,
  payload: authData,
});

export const loginUserSuccess = () => ({
  type: type.LOGIN_USER_SUCCESS,
});

export const loginUserError = error => ({
  type: type.LOGIN_USER_ERROR,
  payload: error,
});

并像这样在我的减速器上使用它:

import * as type from '../types';

const initialState = {
  user: {},
  loading: false,
  error: null,
};

export default function (state = initialState, action) {
  switch (action.type) {
    case type.LOGIN_USER_START:
    case type.REGISTER_USER_START:
      return {
        ...state,
        loading: true,
        user: action.payload,
      };

    case type.LOGIN_USER_SUCCESS:
    case type.REGISTER_USER_SUCCESS:
      return {
        ...state,
        loading: false,
      };
    case type.LOGIN_USER_ERROR:
    case type.REGISTER_USER_ERROR:
      return {
        ...state,
        error: true,
      };
    default:
      return state;
  }
}

最后在我的authSaga:

import * as type from '../types';

import {
  take,
  takeEvery,
  takeLatest,
  put,
  all,
  delay,
  fork,
  call,
} from 'redux-saga/effects';

import {
  loginUserSuccess,
  loginUserError,
} from '../actions/authAction';

import {loginUserApi} from '../services/authApi';

function* onLoginUserStartAsync({payload}) {
  try {
    const response = yield call(loginUserApi, payload);
    if (response.code === 200) {
      yield put(loginUserSuccess(response));
    }
  } catch (error) {
    yield put(loginUserError(error.response));
  }
}


function* onLoginUser() {
  yield take(type.LOGIN_USER_START, onLoginUserStartAsync);
}


const authSagas = [fork(onLoginUser)];

export default function* rootSaga() {
  yield all([...authSagas]);
}

然后我在登录时调用了这个:

import {useDispatch} from 'react-redux';
import * as authAction from '../../redux/actions/authAction';

const LoginScreen: React.FC<Props> = navData => {
  const navigateTo = (destinationScreen: string) =>
    navData.navigation.navigate(destinationScreen);

  const dispatch: any = useDispatch();

  return (
    <TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
      <View style={styles.keyboardView}>
        <Formik
          initialValues={{
            email: '',
            password: '',
          }}
          onSubmit={values => {
            dispatch(authAction.loginUserStart(values)).then(
              async (response: any) => {
                console.log('result from LoginScreen >>>', response);

                if (response.code == 200) {
                  try {
                    await AsyncStorage.setItem('token', response.token);
                    navigateTo('HomeScreen');
                  } catch (error) {
                    console.log(error);
                  }
                } else {
                  Alert.alert('Error!', 'Invalid email and password!', [
                    {text: 'Ok, I understand!'},
                  ]);
                }
              },
            );
          }}

当我尝试使用正确的凭据登录时,这会引发错误:

Warning: An unhandled error was caught from submitForm() TypeError: dispatch(...).then is not a function
    at onSubmit (LoginScreen.tsx:47)
    at formik.cjs.development.js:948
    at formik.cjs.development.js:1262
    at formik.cjs.development.js:864
    at tryCallOne (core.js:37)
    at core.js:123
    at JSTimers.js:248
    at _callTimer (JSTimers.js:112)
    at _callReactNativeMicrotasksPass (JSTimers.js:166)
    at MessageQueue.callReactNativeMicrotasks [as _reactNativeMicrotasksCallback] (JSTimers.js:418

知道是什么原因造成的,我该如何解决?为什么我没有收到可以在dispatch.then 中使用的任何数据响应?

【问题讨论】:

    标签: react-native redux redux-saga


    【解决方案1】:

    loginUserStart 不是 thunk,而是普通的动作创建者。调度一个正常的动作是一个同步事件,不会返回一个承诺。您不需要.then 它,因为只有在操作完全处理后才会出现下一行。

    除此之外,我想让你知道你在这里写了一个非常过时的 Redux 风格,并且可能一直在遵循一个过时的教程。
    现代 Redux 不使用 switch..case reducer、ACTION_TYPE 常量或不可变的 reducer 逻辑。此外,您不需要编写动作创建者。结果大约是代码的 1/4。
    请给the official Redux Tutorial a read

    此外,在完成这些之后,您可能需要查看 Redux Toolkit TypeScript QuickStart,它会告诉您如何为您的 useDispatch 挂钩等获取正确的类型。

    【讨论】:

    • 尝试 console.log const response = await dispatch(authAction.loginUserStart(val)); 然后我得到了动作创建者的全部内容:response from LoginScreen &gt;&gt;&gt; {type: 'LOGIN_USER_START', payload: {…}} payload: {email: 'so@gmail.com', password: 'ps34555'} type: "LOGIN_USER_START" [[Prototype]]: Object
    • 如何修复我的代码以使其正常工作,尤其是我实现调用登录 api 的传奇?
    • loginUserStart 是一个动作和调度,它只会给你返回动作。无法将数据从 sagas 传递回您的组件。这就是为什么我们现在不为大多数代码推荐 sagas 的多个原因之一(sagas 过大并且比其他几乎所有东西的普通 thunk 更复杂)。请参阅Redux Style Guide on Thunks and Sagas。一般来说,我真的建议您按照我链接的教程进行操作,因为它将向您展示以现代方式进行 api 调用的多种方法。
    猜你喜欢
    • 2020-10-20
    • 2018-12-21
    • 2017-06-12
    • 2021-07-24
    • 1970-01-01
    • 2022-09-28
    • 2017-06-24
    • 2023-03-28
    • 2018-01-06
    相关资源
    最近更新 更多