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"