繁体   English   中英

使用 React Hooks 等待 Redux 操作

[英]Awaiting Redux Action w/ React Hooks

我正在尝试处理表单提交以在发生数据获取时显示加载组件。 我想在数据加载到我的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));
        });
    }
};

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

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

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

同样使用带有async-await 语法的useEffect()确保将您的async代码包装在另一个闭包中,因为useEffect()需要一个void返回值,否则 Typescript 会抱怨您返回一个 Promise。

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

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

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

商店.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

给这只鸭子(同一个文件中的类型、动作和减速器,在这里查看更多)

// ----------------------------------------------------------------
// 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;
  }
};

我希望对您有所帮助,让我知道它是否适用于您的情况:)

此致

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM