首页 > 解决方案 > 带有 Redux 的 TypeScript。Redux Saga 如何等待 LOAD_SUCCESS 返回并保存数据以备后用

问题描述

我是使用 redux 和 redux-saga 的新手。

将操作发送到 API 时,我无法检索对象的信息。当我在“promocoesSagas”中第一次使用日志时返回null,它只是在LOAD_REQUEST成功后才返回对象,这很明显。我应该采取什么方法让我的应用程序等待接收这些数据?因为如果我调用一个

const promocoesItems = promocoesSagas.data.item;

应用程序因“LOAD_REQUEST”尚未加载数据而中断,第一次返回null。 第一次调用 尝试访问值

我的 useEffect 钩子:

const List = () => {
...

const promocoesSagas = useSelector((state: AppState) => state.promocoes);   
console.log(promocoesSagas);
const promocoesItem = promocoesSagas.data.items;
console.log(promocoesItem);

const dispatch = useDispatch<Dispatch<PromocoesActions>>();

 useEffect(() => {
   (async () => {
     setIsloading(true);
     try {
       dispatch({ type: PromocoesActionTypes.LOAD_REQUEST, payload: query });
     } catch (error) {
       const errorResult: ErrorResult = error;
       if (
         errorResult.result != null &&
         errorResult.result.statusCode === 403
       ) {
         push('/error-403');
         return;
       }
       message.error(errorResult.message);
     }
     setIsloading(false);
  })();
}, [query, refetch]);

   return (...)}

动作.ts

const loadPromocoesAsync = createAsyncAction(
 PromocoesActionTypes.LOAD_REQUEST,
 PromocoesActionTypes.LOAD_SUCCESS,
 PromocoesActionTypes.LOAD_FAILURE,
)<PromocoesQuery, FetchResult<PromocoesModel>, undefined>();

 export { loadPromocoesAsync };

减速器

const INITIAL_STATE: PromocoesState = {
  data: null,
  error: false,
  loading: false,
};

const reducer: Reducer<PromocoesState> = (
  state = INITIAL_STATE,
  action: PromocoesActions,
) => {
  switch (action.type) {
    case PromocoesActionTypes.LOAD_REQUEST:
      return { ...state, loading: true };
    case PromocoesActionTypes.LOAD_SUCCESS:
      return { ...state, loading: false, error: false, data: action.payload };
    case PromocoesActionTypes.LOAD_FAILURE:
      return { ...state, loading: false, error: true };
    default:
      return state;
  }
};

sagas.ts

function* load(action: ReturnType<typeof loadPromocoesAsync.request>) {
  try {
    const query = action.payload;
    const response: FetchResult<PromocoesModel> = yield call(
      api.getPromocoes,
      query,
    );
    yield put(loadPromocoesAsync.success(response));
  } catch (err) {
    yield put(loadPromocoesAsync.failure());
  }
}

export { load };

类型.ts

type PromocoesActions = ActionType<typeof promocoesActions>;

enum PromocoesActionTypes {
  LOAD_REQUEST = 'LOAD_REQUEST',
  LOAD_SUCCESS = 'LOAD_SUCCESS',
  LOAD_FAILURE = 'LOAD_FAILURE',
}

interface PromocoesState {
  readonly data: FetchResult<PromocoesModel> | null;
  readonly loading: boolean;
  readonly error: boolean;
}

export { PromocoesActions, PromocoesActionTypes, PromocoesState };

根减速器

const rootReducer = combineReducers({
  promocoes,
});

export type AppState = ReturnType<typeof rootReducer>;

export default rootReducer;

根传奇

export default function* rootSaga() {
  return yield all([takeLatest(loadPromocoesAsync.request, load)]);
}

标签: reactjstypescriptreact-reduxreact-hooksredux-saga

解决方案


你几乎准备好了,你只需要在 react 应用程序中处理你的 redux 变量,我建议在List组件中做这样的事情,记住你的 promocoes reducer 已经有 loading 或 error 变量:

// Here you grab the values from the store, you don't need any local state.
const {data, loading, error, } = useSelector((state: AppState) => state.promocoes);

const dispatch = useDispatch<Dispatch<PromocoesActions>>();

// Your useEffect can be simplified, because your api call is already handled by the saga

useEffect(() => {
   dispatch({ type: PromocoesActionTypes.LOAD_REQUEST, payload: query });
}, [query, refetch]); 

if (loading) return <p>Loading...</p>

if (error) return message.error(errorResult.message)

// Assuming data is an array
return data && data.length > 0 && (
  // Your component
)

推荐阅读