Need Help Showing Content From Redux Store
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';
exportdefaultfunctionthreadReducer(state = {}, action) {
switch (action.type) {
caseLOADING_THREAD:
return { ...state, loadingThreads: action.payload }; //modifiedcaseADD_THREAD:
return { ...state, lastThreadAdded: action.payload, success: true };
caseGET_THREADS:
return { ...state, threads: action.payload };
caseGET_THREAD:
return { ...state, current: action.payload };
caseCLEAR_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';
exportconstgetThread = (id) => {
returnasync (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';
constThread = (props) => {
const threads = useSelector((state) => state.threads);
const loading = useSelector((state) => state.loadingThreads); //modifiedconst 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></>
)}
</>
);
};
exportdefaultThread;
Solution 2:
I would suggest to have defined initialState for the reducer
instead
state = {}
const initialState = {
current:{},
threads: [],
success: false
}
functionthreadReducer(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:
exportconstuseCustomerRepository = () => {
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"