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

How to dispatch an redux action to load data inside useEffect on page load

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

下面的代码不会抛出错误。但是,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;

在你的调度映射中你有

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

所以不要调用 props.dispatch(fetchRubrics()); 只需调用 props.getRubrics() 或者从 props

解构这个方法
const { rubrics, loading, error, getRubrics } = props;

然后调用 getRubrics()

下面是正确的代码:

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);

这里的问题是您没有正确使用 mapDispatchToProps。您不需要显式设置调度功能,这就是 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>
  )
}

从 v7.1.0 开始使用 hooks provided by react-redux,现在可以不用 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>
  )
};