【问题标题】:Why is this createAsyncThunk behaving strangely?为什么这个 createAsyncThunk 行为异常?
【发布时间】:2020-11-11 08:23:03
【问题描述】:

我对来自 redux 工具包 API 的 createAsyncThunk 有一些问题

export const getPayments = createAsyncThunk('getPayments/all', async ({ rejectWithValue }) => {
    try {
        const response = await fetch(`/payments`, {
            method: 'GET',
            headers: { 'Content-Type': 'application/json' },
        })
        console.log('res:', response)
        return response
    } catch (e) {
        console.log('ERROR:', e)
        rejectWithValue(e)
    }
})

每当我添加 rejectWithValue 作为参数时,它总是在 redux 开发工具中显示为被拒绝。当我删除它时,它总是会实现。这里发生了什么?如果获取错误,我只想在下面调用此函数?为什么总是拒绝它?

编辑:我现在在回复中看到了这个Cannot destructure property 'rejectWithValue' of 'undefined' as it is undefined.,这是有道理的,为什么它总是被拒绝,为什么会发生这种情况以及我该如何解决?

【问题讨论】:

  • 我认为您应该在异步函数中添加第一个属性,例如:async (data, { rejectWithValue })...
  • @AlekseyDubinskiy 但在这种情况下我不需要任何数据?
  • 即使我输入数据,它仍然会触发“已完成”,即使它跳入了 catch 块??
  • 您还需要退回拒绝。 return rejectWithValue(e)
  • 即使您不需要数据,thunkApi 也会作为第二个参数传入该函数。所以就像 JavaScript 中的任何地方一样:如果你关心第二个参数而不是第一个参数,你仍然需要给第一个参数一个名字,否则你永远不会得到第二个参数。不一定是data_ 可能是表明您不关心它的好选择。

标签: javascript reactjs redux redux-toolkit


【解决方案1】:

这里是一个例子,你可以如何做到这一点,正如评论 payload creatorrejectWithValue第二个参数 的属性,并且有效负载创建者需要 返回 rejectWithValue 调用的结果,这里是一个例子:

// toggle reject
const reject = ((shouldReject) => () =>
  (shouldReject = !shouldReject))(true);
// test thunk action creator
const testAsyncThunk = createAsyncThunk(
  'some/test',
  //  arg is the argument passed to the action creator, can be ignored if not used
  async (arg, { rejectWithValue }) => {
    console.log('argument passed to action creator:', arg);
    if (reject()) {
      //return result of rejectWithValue call
      return rejectWithValue('rejected');
    }
    return Promise.resolve('resolved');
  }
);

当您调度使用 createAsyncThunk 创建的 thunk 时,除非您使用 unwrapResult,否则生成的 promise will not reject

这是一个演示该行为的最小应用程序:

import React from 'react';
import ReactDOM from 'react-dom';
import {
  createAsyncThunk,
  unwrapResult,
} from '@reduxjs/toolkit';

import { Provider, useDispatch } from 'react-redux';
import {
  createStore,
  applyMiddleware,
  compose,
} from 'redux';

// toggle reject
const reject = ((shouldReject) => () =>
  (shouldReject = !shouldReject))(true);
// test thunk action creator
const testAsyncThunk = createAsyncThunk(
  'some/test',
  //  arg is the argument passed to the action creator, can be ignored if not used
  async (arg, { rejectWithValue }) => {
    console.log('argument passed to action creator:', arg);
    if (reject()) {
      //return result of rejectWithValue call
      return rejectWithValue('rejected value');
    }
    return Promise.resolve('resolved value');
  }
);

const reducer = (state, { type, payload }) => {
  return state;
};
//creating store with redux devtools and thunk middleware
const composeEnhancers =
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  reducer,
  {},
  composeEnhancers(
    applyMiddleware(
      ({ dispatch, getState }) => (next) => (action) =>
        //minimal implementation of thunk middleware
        typeof action === 'function'
          ? action(dispatch, getState)
          : next(action)
    )
  )
);
const App = () => {
  const dispatch = useDispatch();
  return (
    <button
      onClick={() =>
        dispatch(testAsyncThunk('argument passed'))
          .then(
            (resolved) => {
              console.log('action resolved with', resolved);
              return resolved;
            },
            (rejected) =>
              // this never executes because promise returned
              //   by dispatch(tunkaction) will not reject
              console.log('action rejected with:', rejected)
          )
          .then(
            //after unwrap result you have a promise that will
            //  reject
            unwrapResult
          )
          .catch((err) =>
            console.log('rejected with...', err)
          )
      }
    >
      dispatch action
    </button>
  );
};

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

【讨论】:

  • 好的,谢谢。我修好了,但我有一个问题。我在createAsyncThunk 里面有一个 fetch,我在里面放了一个 try catch,它从来没有“拒绝”它。即使它进入了 catch 块。但是当我删除 try/catch 并刚刚从 fetch 返回结果时。有效? (即根据服务器响应,它要么转到.fulfilled.rejected。为什么try/catch 不起作用?
  • @RedBaron 你确定返回 return rejectWithValue(someError); 在你的 catch 块中吗?
  • 不,我想这可能有效。稍后会尝试 n 让你知道
猜你喜欢
  • 2014-04-23
  • 2014-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多