如何在页面加载时调度 redux 操作以在 useEffect 中加载数据

Posted

技术标签:

【中文标题】如何在页面加载时调度 redux 操作以在 useEffect 中加载数据【英文标题】:How to dispatch an redux action to load data inside useEffect on page load 【发布时间】:2019-09-02 04:08:18 【问题描述】:

我正在尝试将 redux 集成到现有的 react 应用程序中。我正在学习redux。我正在使用钩子。在互联网上有很多使用类组件的例子。我找不到如何使用功能组件实现此目的的示例。

下面的代码不会抛出错误。但是,useEffect 内部的动作没有被调用。该代码不产生任何输出。我想知道电话是否正确。有什么帮助吗?

Index.js

const store = createStore(rubricReducer, applyMiddleware(thunk));     
ReactDOM.render(
    <BrowserRouter basename=baseUrl>
        <Provider store=store > <App /> </Provider>
        </BrowserRouter>,
    rootElement);

Rubrics.tsx

const mapStateToProps = state => (
    rubrics: state.rubrics.items,
    loading: state.rubrics.loading,
    error: state.rubrics.error
);

const mapDispatchToProps = (dispatch) => 
    return 
        getRubrics: () => dispatch(fetchRubrics())
    ;


const Rubrics = (props) =>     
    const  rubrics, loading, error  = props;

    useEffect(() => 
        props.dispatch(fetchRubrics());
    , []);    

    if (error)  return <div>Error! error.message</div>;     
    if (loading)  return <div>Loading...</div>;     

    return (    
        <ul>
            <React.Fragment>
                rubrics.map(rubric => 
                        return (
                            <li key=rubric.id>rubric.title</li>

                        );
                    )
            </React.Fragment>
        </ul>
    )


export default connect(mapStateToProps, mapDispatchToProps)(Rubrics);

rubricActions.tsx:

export function fetchRubrics() 
    return dispatch => 
        dispatch(fetchRubricsBegin());

        axios.get("api/Rubric/Index")
            .then(response => 
                console.log('success: reading rubrics');

                dispatch(fetchRubricsSuccess(response.data));
                return response.data;
            )
            .catch(error =>  fetchRubricsFailure(error) );
    ;


export const FETCH_RUBRICS_BEGIN = "FETCH_RUBRICS_BEGIN";
export const FETCH_RUBRICS_SUCCESS = "FETCH_RUBRICS_SUCCESS";
export const FETCH_RUBRICS_FAILURE = "FETCH_RUBRICS_FAILURE";

const fetchRubricsBegin = () => (
    type: FETCH_RUBRICS_BEGIN
)

const fetchRubricsSuccess= (rubrics) => (
    type: FETCH_RUBRICS_SUCCESS,
    payload:  rubrics
)


const fetchRubricsFailure = (error) => (
    type: FETCH_RUBRICS_FAILURE,
    payload: error
)

rubricReducer.tsx

import 
    FETCH_RUBRICS_BEGIN,
    FETCH_RUBRICS_SUCCESS,
    FETCH_RUBRICS_FAILURE
 from '../_actions/rubricActions';

const initialState = 
    rubrics: [],
    loading: false,
    error: null
;

const rubricReducer = (state = initialState, action) => 
    switch (action.type) 
        case FETCH_RUBRICS_BEGIN:
            return 
                ...state,
                loading: true,
                error: null
            ;

        case FETCH_RUBRICS_SUCCESS:
            return 
                ...state,
                loading: false,
                items: action.payload.rubrics
            
        case FETCH_RUBRICS_FAILURE:
            return 
                ...state,
                loading: false,
                error: action.payload.error,
                items: []
            ;
        default:
            return state;
    

export default rubricReducer;

【问题讨论】:

useEffect 对我来说看起来不错。您可能想检查fetchRubrics 是否工作正常。 【参考方案1】:

在您的调度映射中,您有

const mapDispatchToProps = (dispatch) => 
    return 
        getRubrics: () => dispatch(fetchRubrics())
    ;

所以不要调用props.dispatch(fetchRubrics()); 只需调用props.getRubrics() 或从道具中解构此方法

const  rubrics, loading, error, getRubrics  = props;

只需拨打getRubrics()

【讨论】:

FETCH_RUBRICS_BEGIN 动作是否被调度?这也可能是一个愚蠢的问题,但我假设您使用 redux-thunk 或任何类似的中间件?【参考方案2】:

下面是正确的代码:

const Rubrics = (props) => 

    useEffect(() => 
        props.fetchAllRubrics();
    , [])


    return (
        props.rubrics.map((rubric) => 
            return (<RubricCard rubric=rubric />)
        )
    )


const mapStateToProps = state => (
    error: state.error,
    rubrics: state.rubrics,
    loading: state.oading
)

const mapDispatchToProps = dispatch => 
    return  fetchAllRubrics: () => dispatch(fetchRubricsData()) 


export default connect(
    mapStateToProps,
    mapDispatchToProps
)(Rubrics);

【讨论】:

【参考方案3】:

这里的问题是您使用了不正确的 mapDispatchToProps。你不需要显式设置 dispatch 函数,这就是 react redux 为你做的。

所以,下面是正确的做法:

// Now you won't be creating a new object every time your component re-renders
const mapDispatchToProps = 
  getRubrics: fetchRubrics


const Rubrics = (props) =>     
  const  getRubrics  = props;

  // You should always add elements inside your render scope
  // to the second array parameter of useEffect to prevent unexpected bugs.
  useEffect(() => 
      getRubrics();
  , [getRubrics]);

  return (    
    <div>Your component here!</div>
  )

【讨论】:

【参考方案4】:

使用自 v7.1.0 起由react-redux 提供的hooks,现在可以在没有mapStateToPropsmapDispatchToProps 的情况下编写。

import React,  useEffect  from 'react';
import  useDispatch, useSelector  from 'react-redux';


const Rubrics = () => 
  const dispatch = useDispatch();

  const  rubrics, loading, error  = useSelector(
    state => (
      error: state.error,
      rubrics: state.rubrics,
      loading: state.loading
    )
  );

  useEffect(() => 
    dispatch(fetchRubrics());
  , [dispatch]);

  if (error)  return <div>Error! error.message</div>; 
  if (loading)  return <div>Loading...</div>; 

  return (
    <ul>
      <React.Fragment>
        rubrics.map(rubric => 
          return (
            <li key=rubric.id>rubric.title</li>
          );
        )
      </React.Fragment>
    </ul>
  )
;

【讨论】:

明智的做法是 useEffect 包含 dispatch 作为依赖项 您知道,我在编码const dispatch = useDispatch; 时遇到了错误,并且出现了“无效的挂钩调用”错误。刚刚编码了```const dispatch = useDispatch();带括号,效果很好。真是个疯子。

以上是关于如何在页面加载时调度 redux 操作以在 useEffect 中加载数据的主要内容,如果未能解决你的问题,请参考以下文章

使用 React-Router 和 Redux 时单击链接时如何调度操作?

如何在 getInitialProps 中使用 redux 钩子

如何使用 Redux 只更新组件的一个实例?

使用 TypeScript 在 Chrome 扩展背景页面中调度 Redux 操作

useEffect TypeScript 错误中的 Redux 操作?

即使没有分派任何操作,Redux 状态也会在加载时更改