等待带有 React Hooks 的 Redux Action

Posted

技术标签:

【中文标题】等待带有 React Hooks 的 Redux Action【英文标题】:Awaiting Redux Action w/ React Hooks 【发布时间】:2019-10-23 05:42:24 【问题描述】:

我正在尝试处理表单提交以在数据获取发生时显示加载组件。我想在数据加载到我的Redux 商店时显示数据。

现在,我已将组件设置为使用 React 挂钩。虽然数据成功加载到我的redux 存储中,但我不确定如何“等待”操作完成的结果。这是我的组件的简化版本:

const DataPage = (props) => 

    const [isLoading, setIsLoading] = useState(false);
    const [isError, setError] = useState(false);

    useEffect(() =>  // Reset Filters when dataSource changes...
        setError(false);
        setIsLoading(false);
    , [dataSource]);

    const handleSubmit = (e,  dataSource ) => 

        e.preventDefault();
        setError(false)
        setIsLoading(true);

         //// IDEALLY THIS IS WHERE THE FIX WOULD GO? TURN THIS INTO ASYNC/AWAIT?
        props.fetchData( dataSource, token: localStorage.JWT_TOKEN );
    ;

    return (    
        <div className="dataPage">
            <form className="dataPage__filters" onSubmit=(e) => handleSubmit(e,  dataSource )>
                <DataSelector dataSource=dataSource setDataSource=setDataSource/>
                <button className="button">
                   Search
                </button>
            </form>
            isError && <div>Something went wrong...</div>
             isLoading ? ( <div>...Loading </div> ) : (
                <div className="dataPage__table">
                    <DataTable /> // This is connected to my redux-store separately through 'connect'
                </div>
            )
        </div>
    );
;

const mapDispatchToProps = (dispatch) => (
    fetchData: ( dataSource, token ) => dispatch(startFetchData( dataSource, token ))
);

export default connect(null, mapDispatchToProps)(DataPage);

相关操作(startFetchDatasetData)位于另一个文件中,如下所示:

export const setData = (data) => (
    type: "SET_DATA",
    data
);

export const startFetchData = ( dataSource, filter, filterTarget, token ) => 
    return (dispatch) => 

        axios.get(`$'http://localhost:8081'/api/$dataSource`,  headers:  authorization: token )
        .then((res) => 
            dispatch(setData(result));
        );
    
;

如果可能的话,我希望能够在不引入任何新依赖项的情况下做到这一点。

【问题讨论】:

从 redux 调度动作修改/更新状态值可能被认为是工作 react-redux 的反模式,您应该考虑将 loading 移动到页面的减速器中并简单地从那里调度动作, loading 现在将成为道具 对不起,我不明白这条评论。即使我将 isLoading 作为道具传递给我的 DataTable,也不能解决我的问题。我仍在尝试等待 fetchData redux 操作。 【参考方案1】:

使用 TypeScript 的注意事项:如果你想 await 使用 useDispatch() 的操作返回的承诺,你可能会看到 TypeScript 抱怨不必要的 await

在这种情况下,请确保通过泛型将正确的类型(参见 ThunkDispatch)添加到 useDispatch

还有useEffect() 和async-await syntax 确保将async 代码包装在另一个闭包中,因为useEffect() 期望void 返回值,否则Typescript 会抱怨您返回Promise。

const dispatch = useDispatch<ThunkDispatch<any, any, Action>>();

useEffect(() => 
  (async () => 
    const myResult = await dispatch(...);
    const anotherResult = await dispatch(...);
    // ...
  )();
);

【讨论】:

【参考方案2】:

我推荐你使用redux-thunk 中间件。这是一个非常简单且有用的库,可以让您的操作成为函数(包括异步函数),而不是对象。我给你举个例子:

Store.js

import  createStore, applyMiddleware  from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
import api from './services/api';

// Note: this API requires redux@>=3.1.0
const store = createStore(
  rootReducer,
  // With extra argument, in this case, my API):
  applyMiddleware(thunk.withExtraArgument(api));
);

AuthDuck.js

给这只鸭子(类型、动作和reducers在同一个文件中,查看更多here)

// ----------------------------------------------------------------
// Types
// ----------------------------------------------------------------
const Types = 
  SIGN_IN_START: 'SIGN_IN_START',
  SIGN_IN_SUCCESS: 'SIGN_IN_SUCCESS',
  SIGN_IN_FAIL: 'SIGN_IN_FAIL'
;

// ----------------------------------------------------------------
// Actions
// ----------------------------------------------------------------
const signin = function (user) 
  // LOOK HERE!
  // Redux Thunk able you to return a function instead of an object.
  return async function (dispatch, getState, api) 
    try 
      dispatch( type: Types.SIGN_IN_START );
      const token = await api.access.signin(user);
      dispatch( type: Types.SIGN_IN_SUCCESS, payload: token );
     catch (error) 
      dispatch( type: Types.SIGN_IN_FAIL, payload: error );
    
  ;
;

export const Actions =  signin ;

// ----------------------------------------------------------------
// Reducers
// ----------------------------------------------------------------
export default function reducer(state, action) 
  switch (action.type) 
    case VeasyCalendarTypes.SIGN_IN_START:
      return  ...state, isLoading: true ;
    case VeasyCalendarTypes.SIGN_IN_SUCCESS:
      return  ...state, isLoading: false, token: action.payload ;
    case VeasyCalendarTypes.SIGN_IN_FAIL:
      return  ...state, isLoading: false, error: action.payload ;
    default:
      return state;
  
;

我希望对你有所帮助,如果它对你的情况有用,请告诉我:)

最好的问候

【讨论】:

以上是关于等待带有 React Hooks 的 Redux Action的主要内容,如果未能解决你的问题,请参考以下文章

Redux-Toolkit 和 React Hooks - 存储更改不会触发重新渲染

React - Redux Hooks的使用细节详解

React Hooks 与 React-redux

react+redux+hooks

使用react-router+hooks搭建基础框架

使用 React-Redux Hooks 和 React-Redux Connect() 的主要区别是啥?