使用React Hooks与Redux实现POST请求受阻,寻求技术解决方案
Hey there, let's work through the issues in your code step by step to get that POST request working and fill in the Redux integration gaps you're missing.
1. Fix the Redux dispatch setup in App.js
Right now, your addPost action isn't actually being dispatched to Redux because your connect call isn't mapping the action to your component's props. You have two clean ways to fix this:
Option A: Use useDispatch (Hooks-style, more modern)
Ditch the connect wrapper entirely and use the useDispatch hook just like you do in the Posts component:
import { useState, useDispatch } from "react"; import "./App.css"; import Posts from "./components/posts"; import { addPost } from "./store/actions/postAction"; function App() { const [title, setTitle] = useState(""); const [body, setBody] = useState(""); const dispatch = useDispatch(); // Add this line const handleSubmit = (event) => { event.preventDefault(); const post = { title, body }; dispatch(addPost(post)); // Wrap addPost with dispatch setTitle(''); setBody(''); alert("Post added!"); }; // ... rest of your component code } export default App; // No need for connect anymore
Option B: Use mapDispatchToProps with connect
If you prefer keeping connect, map the action to props:
// At the bottom of App.js const mapDispatchToProps = { addPost }; export default connect(null, mapDispatchToProps)(App); // Then in handleSubmit, call props.addPost(post): const handleSubmit = (event) => { event.preventDefault(); const post = { title, body }; props.addPost(post); // Now this will dispatch the action // ... rest of code };
2. Fix the async POST request in postAction.js
Your addPost action has two critical issues:
- You're not awaiting the
axios.postcall, so you'll try to accessresponse.databefore the request completes - The POST URL is likely incorrect (you're sending to
http://localhost:8002/instead of/posts) - You're wrapping the post in an extra
{post}object unless your backend explicitly expects that structure
Here's the fixed version:
import axios from "axios"; import { GET_POSTS, ADD_POST, POSTS_ERROR, POSTS_LOADING } from "../types"; const url = "http://localhost:8002/"; // Add this action type if you haven't already for loading state export const getPosts = () => async (dispatch) => { try { dispatch({ type: POSTS_LOADING }); // Set loading to true before fetch const response = await axios.get(`${url}posts`); dispatch({ type: GET_POSTS, payload: response.data, }); } catch (error) { dispatch({ type: POSTS_ERROR, payload: error.message, // Store the error message instead of the full error object }); } }; export const addPost = (post) => async (dispatch) => { // Mark as async try { dispatch({ type: POSTS_LOADING }); const response = await axios.post(`${url}posts`, post); // Fix URL and remove extra wrapping dispatch({ type: ADD_POST, payload: response.data, }); } catch (error) { dispatch({ type: POSTS_ERROR, payload: error.message, }); } };
3. Fix state updates and initial state in postReducer.js
Your reducer is missing loading/error state fields, and the ADD_POST case is replacing the entire posts array instead of adding the new post to it. Here's the corrected reducer:
import { ADD_POST, GET_POSTS, POSTS_ERROR, POSTS_LOADING } from "../types"; // Add loading and error to initial state const initialState = { posts: [], loading: false, error: null }; const postReducer = (state = initialState, action) => { switch (action.type) { case POSTS_LOADING: return { ...state, loading: true, error: null }; case GET_POSTS: return { ...state, posts: action.payload, loading: false, error: null }; case ADD_POST: // Add the new post to the existing array instead of replacing it return { ...state, posts: [...state.posts, action.payload], loading: false }; case POSTS_ERROR: return { ...state, loading: false, error: action.payload }; default: return state; } }; export default postReducer;
4. Fix state selector in posts.js
Double-check that your selector matches the key you used for the post reducer in your root reducer. For example, if your root reducer looks like this:
import { combineReducers } from 'redux'; import postReducer from './postReducer'; export default combineReducers({ posts: postReducer // Key is "posts" });
Then update your selector in Posts to:
const postsList = useSelector((state) => state.posts); // Not state.postsList
5. Quick backend check
Make sure your backend endpoint http://localhost:8002/posts accepts POST requests, and that it's configured to parse JSON request bodies (e.g., using express.json() if you're using Express.js).
Once you apply these fixes, your POST request should send data correctly, Redux will update the state with the new post, and your Posts component will display it automatically.
内容的提问来源于stack exchange,提问作者istoby

