Skip to content Skip to sidebar Skip to footer

Need Help Showing Content From Redux Store

I am trying to retrieve information from my backend and display it. I can fetch the data to my redux store fine but when I try to display it on the page I get a cannot read propert

Solution 1:

The reason it's happening is because the action you are dispatching is Async (dispatch(getThread(props.match.params.id));) and hence code execution will not wait for the API result it will execute the next statement which is setLoading(false). You are making your loading stop before API response and hence you are getting undefined error.

Answer :

Reduder:

import { ADD_THREAD, GET_THREADS, GET_THREAD, CLEAR_THREAD, LOADING_THREAD } from '../types';

export default function threadReducer(state = {}, action) {
  switch (action.type) {
    case LOADING_THREAD:
      return { ...state, loadingThreads: action.payload }; //modified
    case ADD_THREAD:
      return { ...state, lastThreadAdded: action.payload, success: true };
    case GET_THREADS:
      return { ...state, threads: action.payload };
    case GET_THREAD:
      return { ...state, current: action.payload };
    case CLEAR_THREAD:
      return { ...state, current: null };

    default:
      return state;
  }
}

Action:

import * as threads from './index';
import axios from 'axios';
import { getAuthHeaders } from '../../components/utils/tools';

axios.defaults.headers.post['Content-Type'] = 'application/json';

export const getThread = (id) => {
  return async (dispatch) => {
try {
    dispatch(threads.loadingThread(true));
    const request = await axios.get(`/forum/thread/${id}`);
    dispatch(threads.getThread(request.data));
    dispatch(threads.loadingThread(false));

    
    } catch (error) {
    dispatch(threads.loadingThread(false));
      dispatch(threads.errorGlobal('Error retrieving thread'));
    }
  };
};

Component:

import '../../styles/article.css';
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getThread } from '../../store/actions/forum_actions';
import { clearThread } from '../../store/actions';
const Thread = (props) => {
  const threads = useSelector((state) => state.threads);
  const loading = useSelector((state) => state.loadingThreads); //modified
  const thread = threads?.current;
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(getThread(props.match.params.id));
    setLoading(false);
  }, [dispatch, props.match.params.id]);

  useEffect(() => {
    return () => {
      dispatch(clearThread());
    };
  }, [dispatch]);

  return (
    <>
      {loading ? (
        <>
          <p>Loading</p>
        </>
      ) : (
        <>
          <p>{thread.title}</p>
        </>
      )}
    </>
  );
};

export default Thread;

Solution 2:

I would suggest to have defined initialState for the reducer

instead

state = {}

const initialState = {
current:{},
threads: [],
success: false 
}

function threadReducer(state = initialState, action)

this will help you managing the in-between state.

Also loading state in the component is not always aligned. Consider using

isLoading = useSelector(loadingSelector)

instead useState


Solution 3:

You can simplify Redux async flows implementing the repository pattern without a middleware to handle an API call and dispatch a state. Api calls can be also encapsulated into hooks. For example, take a look to this piece of code, it's not related to your project, but you can use it as a starting point:

export const useCustomerRepository = () => {
  const dispatch = useDispatch<Dispatch<CustomerAction>>();

  const customerState = useSelector((state: RootState) => state.customerState);
  const customerApi = useCustomerApi();

  const list = async () => {
    try {
      dispatch({ type: 'CUSTOMER:LISTING', flag: true });
      const customers = await handleAxiosApi<Customer[]>(customerApi.list());
      dispatch({ type: 'CUSTOMER:LIST', customers });
    } catch (error) {
      dispatch({ type: 'CUSTOMER:LIST_FAILED', message: getResponseErrorMessage(error) });
    } finally {
      dispatch({ type: 'CUSTOMER:LISTING', flag: false });
    }
  };

  return {...customerState};
};

You can take a look to the full working example here to simplify your code.


Post a Comment for "Need Help Showing Content From Redux Store"