Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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. I am learning 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. The code does not produce any output. I wonder if the call is correct or not. Any help?

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;
like image 354
renakre Avatar asked Apr 11 '19 13:04

renakre


People also ask

Can we dispatch action in useEffect?

Note: React guarantees that dispatch function identity is stable and won't change on re-renders. This is why it's safe to omit from the useEffect or useCallback dependency list. You would need to pass either bound action creators or a reference to dispatch to your hook.

What is an action in Redux can I dispatch an action in reducer?

Dispatching an action within a reducer is an anti-pattern. Your reducer should be without side effects, simply digesting the action payload and returning a new state object. Adding listeners and dispatching actions within the reducer can lead to chained actions and other side effects.

What is return inside useEffect?

The return function is the cleanup function, or when the user leaves the page and the component will unmount. The array is the last part, and it is where you put the states that will update throughout the component's lifecycle. You can discard the array if your component won't update during its lifecycle.


1 Answers

With the hooks provided by react-redux since v7.1.0, this can be now written without mapStateToProps and mapDispatchToProps.

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>
  )
};
like image 51
Rüdiger Schulz Avatar answered Oct 02 '22 18:10

Rüdiger Schulz