需要帮助显示内容从redux存储



我试图从我的后端检索信息并显示它。我可以获取数据到我的redux存储很好,但当我试图在页面上显示它时,我得到一个无法读取属性"标题"的未定义错误。并不总是出现,但每当我刷新它就会出现。什么好主意吗?这是有问题的文件。很高兴分享其他信息,但我很有信心我的后端和redux都工作正常,因为我可以在其他地方检索和显示数据。

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 [loading, setLoading] = useState(true);
const threads = useSelector((state) => state.threads);
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;

这里是减速器:

import { ADD_THREAD, GET_THREADS, GET_THREAD, CLEAR_THREAD } from '../types';
export default function threadReducer(state = {}, action) {
switch (action.type) {
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;
}
}

动作

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) => {
const request = await axios.get(`/forum/thread/${id}`);
dispatch(threads.getThread(request.data));
try {
} catch (error) {
dispatch(threads.errorGlobal('Error retrieving thread'));
}
};
};

发生的原因是因为你正在调度的动作是Async (dispatch(getThread(props.match.params.id));),因此代码执行将不会等待API结果,它将执行下一个语句,即setLoading(false)。你正在使你的加载在API响应之前停止,因此你得到未定义的错误。

解决方案:

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

行动:

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

组件:

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;

我建议为reducer定义initialState

而不是state = {}

const initialState = {
current:{},
threads: [],
success: false 
}
function threadReducer(state = initialState, action)

这将帮助您管理中间状态。

组件中的加载状态也不总是对齐的。考虑使用

isLoading = useSelector(loadingSelector)

代替useState

您可以简化实现存储库模式的Redux异步流,而不需要中间件来处理API调用和分派状态。Api调用也可以封装到钩子中。例如,看看这段代码,它与您的项目无关,但您可以将其用作起点:

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

您可以查看这里的完整工作示例,以简化您的代码。

最新更新