React组件调用Axios无请求,新闻数据无法加载问题排查
问题描述
正在为网站开发新闻栏模块,用于展示站点更新内容片段。已完成后端数据Schema、Post与Get请求路由开发,前端采用Axios处理请求、Redux管理全局状态、配置CORS。通过NewsBar组件嵌套NewsPosts组件渲染新闻内容,但目前控制台仅输出NewsPosts相关日志,未发起任何网络请求,Redux中的newsPosts为空对象,无法获取预期的新闻数据,请求排查原因。
相关代码
NewsBar组件
function useQuery() { return new URLSearchParams(useLocation().search); } const NewsBar = () => { const classes = useStyles(); const query = useQuery(); const page = query.get('page') || 1; const searchQuery = query.get('searchQuery'); const [currentId, setCurrentId] = useState(0); console.log(`NewsBar: ${useLocation().search} | query=>${query}`); console.log(`searchquery: ${searchQuery}`); return ( <> <Grow in> <Grid container direction={'row'} className={classes.newsBar} justifyContent='center'> <Typography variant='h3'>News Bar</Typography> <Grid item> <NewsPosts setCurrentId={setCurrentId} /> </Grid> </Grid> </Grow> </> ) } export default NewsBar;
NewsPosts组件
const NewsPosts = ({ setCurrentId }) => { const { newsPosts, isLoading } = useSelector((state) => state.newsPosts); const classes = useStyles(); newsPosts.map((newsPost) => { console.log(newsPost); }) console.log(new Date().toISOString()); console.log(`newsPosts array: ${typeof newsPosts} ${newsPosts}`) if (!newsPosts.length && !isLoading) return 'No news posts.'; return ( isLoading ? <LinearProgress /> : ( <Grid container alignItems='stretch' spacing={3}> {newsPosts?.map((newsPost) => ( <Grid key={newsPost._id} item xs={12} sm={12} md={12} lg={12}> <NewsPost newsPost={newsPost} setCurrentId={setCurrentId}/> </Grid> ))} </Grid> ) ); }; export default NewsPosts;
控制台日志
NewsBar: | query=> NewsBar.js:27 searchquery: null NewsPosts.js:17 2022-12-01T20:36:08.958Z NewsPosts.js:18 newsPosts array: object
Redux Actions代码
import { START_LOADING, END_LOADING, FETCH_POST, FETCH_ALL, DELETE, CREATE } from "../constants/actionTypes"; import * as api from '../api/index.js'; //CREATE ACTIONS -> should follow the standard XMLHTTPRequest operation export const getNewsPost = (id) => async (dispatch) => { try { console.log('actions: action getNewsPost was called'); dispatch({ type: START_LOADING }) const { data } = await api.fetchNewsPost(id); dispatch({type: FETCH_POST, payload: { newsPost: data }}); console.log(`got post ${data}`); } catch (error) { console.log(error); } }; export const getNewsPosts = (page) => async (dispatch) => { try { console.log('actions: action getNewsPosts was called'); dispatch({ type: START_LOADING }); const {data : {data, currentPage, numberOfPages }} = await api.fetchNewsPosts(page); dispatch({ type: FETCH_ALL, payload: { data, currentPage, numberOfPages }}); dispatch({ type: END_LOADING }); } catch (error) { console.log(error); } }; export const createNewsPost = (newsPost, history) => async (dispatch) => { try { console.log('actions: action createNewsPosts was called'); dispatch({ type: START_LOADING }); const { data } = await api.createNewsPost(newsPost); dispatch({ type: CREATE, payload: data }); history.push(`/newsPosts/${data._id}`); } catch (error) { console.log(error); } }; export const deleteNewsPost = (id) => async (dispatch) => { try { console.log('actions: action deleteNewsPost was called'); await await api.deletePost(id); dispatch({ type: DELETE, payload: id }); } catch (error) { console.log(error); } };
API配置代码
import axios from 'axios'; const API = axios.create({ baseURL: 'http://localhost:5000' }); API.interceptors.request.use((req) => { if (localStorage.getItem('profile')) { req.headers.Authorization = `Bearer ${JSON.parse(localStorage.getItem('profile')).token}`; } return req; }); export const fetchPost = (id) => API.get(`/posts/${id}`); export const fetchPosts = (page) => API.get(`/posts?page=${page}`); export const fetchPostsByCreator = (name) => API.get(`/posts/creator?name=${name}`); export const fetchPostsBySearch = (searchQuery) => API.get(`/posts/search?searchQuery=${searchQuery.search || 'none'}&tags=${searchQuery.tags}`); export const createPost = (newPost) => API.post('/posts', newPost); export const likePost = (id) => API.patch(`/posts/${id}/likePost`); export const comment = (value, id) => API.post(`/posts/${id}/commentPost`, { value }); export const updatePost = (id, updatedPost) => API.patch(`/posts/${id}`, updatedPost); export const deletePost = (id) => API.delete(`/posts/${id}`); export const signIn = (formData) => API.post('/user/signin', formData); export const signUp = (formData) => API.post('/user/signup', formData); export const fetchNewsPost = (id) => API.get(`/news/${id}`); export const fetchNewsPosts = (page) => API.get(`/news?page=${page}`); export const createNewsPost = (newNewsPost) => API.post('/news', newNewsPost); export const deleteNewsPost = (id) => API.delete(`/news/${id}`);
解决方案
1. 触发数据加载Action
当前代码未调用getNewsPosts Action,导致无网络请求发起。需在组件中通过useDispatch和useEffect触发请求:
修改NewsPosts组件:
import { useDispatch } from 'react-redux'; import { getNewsPosts } from '../actions/newsActions'; // 按实际路径调整 import { useEffect } from 'react'; const NewsPosts = ({ setCurrentId }) => { const { newsPosts, isLoading } = useSelector((state) => state.newsPosts); const dispatch = useDispatch(); const classes = useStyles(); // 组件挂载时发起请求 useEffect(() => { dispatch(getNewsPosts(1)); // 可传入page参数,比如从父组件接收 }, [dispatch]); // 防止非数组类型调用数组方法 if (!Array.isArray(newsPosts)) return '数据格式异常'; console.log(new Date().toISOString()); console.log(`newsPosts array: ${typeof newsPosts} ${newsPosts}`) if (!newsPosts.length && !isLoading) return '暂无新闻内容'; return ( isLoading ? <LinearProgress /> : ( <Grid container alignItems='stretch' spacing={3}> {newsPosts.map((newsPost) => ( <Grid key={newsPost._id} item xs={12} sm={12} md={12} lg={12}> <NewsPost newsPost={newsPost} setCurrentId={setCurrentId}/> </Grid> ))} </Grid> ) ); }; export default NewsPosts;
或在NewsBar中触发并传递page参数:
const NewsBar = () => { // ... 原有代码 const dispatch = useDispatch(); useEffect(() => { dispatch(getNewsPosts(page)); }, [dispatch, page]); // ... 原有return逻辑 }
2. 修正Redux初始状态
控制台显示newsPosts为对象,说明Reducer初始状态错误,需将newsPosts设为数组:
// newsReducer.js const initialState = { newsPosts: [], isLoading: false, currentPage: 1, numberOfPages: 1 }; export default (state = initialState, action) => { switch (action.type) { case FETCH_ALL: return { ...state, newsPosts: action.payload.data, currentPage: action.payload.currentPage, numberOfPages: action.payload.numberOfPages }; // 其他case逻辑 default: return state; } };
3. 修复Delete Action的API调用错误
deleteNewsPost Action存在冗余await和错误API调用:
export const deleteNewsPost = (id) => async (dispatch) => { try { console.log('actions: action deleteNewsPost was called'); await api.deleteNewsPost(id); // 去掉多余await,调用新闻专属删除接口 dispatch({ type: DELETE, payload: id }); } catch (error) { console.log(error); } };
内容的提问来源于stack exchange,提问作者Zachery Uporsky
相关产品推荐
相关产品推荐

