简体   繁体   English

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

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

I am trying to integrate redux to an existing react application.我正在尝试将 redux 集成到现有的反应应用程序中。 I am learning redux.我正在学习 redux。 I am using hooks.我正在使用钩子。 In the internet there are many examples of using class components.在互联网上有很多使用类组件的例子。 I could not find an example how to achieve this with a function component.我找不到如何使用功能组件实现此目的的示例。

The code below does not throw an error.下面的代码不会引发错误。 But, the action inside useEffect is not called.但是,不会调用useEffect中的操作。 The code does not produce any output.该代码不产生任何输出。 I wonder if the call is correct or not.我想知道这个电话是否正确。 Any help?有什么帮助吗?

Index.js索引.js

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

Rubrics.tsx 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: 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 : 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;

With the hooks provided by react-redux since v7.1.0, this can be now written without mapStateToProps and mapDispatchToProps .使用react-redux从 v7.1.0 开始提供的钩子,现在可以在没有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>
  )
};

The problem here is that you are using incorrectly mapDispatchToProps.这里的问题是您使用的 mapDispatchToProps 不正确。 You don't need to set explicitly the dispatch function, that is what react redux does for you.您不需要显式设置调度功能,这就是 react redux 为您所做的。

So, below is the correct way to do it:所以,下面是正确的做法:

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

In your dispatch mapping you have在您的调度映射中,您有

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

so instead of calling props.dispatch(fetchRubrics());所以不是调用props.dispatch(fetchRubrics()); just call props.getRubrics() or destructurize this method from props只需调用props.getRubrics()或从道具中解构此方法

const { rubrics, loading, error, getRubrics } = props;

and just call getRubrics()只需调用getRubrics()

Below is the correct code:下面是正确的代码:

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

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

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