我的代码流程是,用户填写表单并提交,然后转到调用API的Action,然后返回postId并将其存储在reducer中。现在我的主 React 类使用 useSelector 来获取 postId 的最新状态。因此,在调用操作并提交表单后,我通过“/classifieds/{postId}”导航到该帖子,但 postId 在 handleSubmit 函数内显示 null,而在该函数外部显示 postId 的值。所以可能我的思维方式是错误的。有人可以帮我建议流程应该如何吗?
这是classifieds.js
import React, { useEffect, useState } from "react";
import { TextEditor } from "../../../components/Text-Editor/text-editor";
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import InputGroup from 'react-bootstrap/InputGroup';
import { useDispatch, useSelector } from "react-redux";
import { getCategories, postClassifieds } from "../../../redux/actions/classifiedsAction";
import './post-classified.scss'
import { useNavigate } from "react-router-dom";
export const PostClassified = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const classifiedsLoading = useSelector((state) => state.classifieds.loading);
const postId = useSelector((state) => state.classifieds.postId);
console.log("postID is 1",postId) // this shows up with the id when handleSubmit is called
const handleInputChange = (e) => {
const { name, value,type,checked } = e.target;
const inputValue = type === 'checkbox' ? checked : value;
setFormData({ ...formData, [name]: inputValue });
};
const [formData, setFormData] = useState({
heading: '',
category:''
});
const [formSubmitMessage,setFormSubmitMessage] = useState(false);
const newFormData = new FormData();
const handleSubmit = async (e) => {
e.preventDefault();
setFormSubmitMessage(false);
newFormData.append("heading",formData.heading);
newFormData.append("category",formData.category);
await dispatch(postClassifieds(newFormData));
console.log("postID is 2",postId) // this shows up null
navigate(`/classifieds/${postId}`)
};
return (
<div className="section properties">
<div className="container">
{ classifiedsLoading ?(<></>):
<Form onSubmit={handleSubmit} encType="multipart/form-data" className="form-post">
{/* form.............. */}
</Form>
}
</div>
</div>
);
}
这是classifiedsAction.js
import axios from "axios";
export const POST_SUCCESS = "POST_SUCCESS";
export const POST_FAILURE = "POST_FAILURE";
export const CLASSIFIEDS_LOADING = "CLASSIFIEDS_LOADING";
// post classified
export const postClassifieds = (formData) => async(dispatch) => {
try{
const response = await axios.post('/posts', formData);
dispatch({
type: 'POST_SUCCESS',
payload: response.data._id, // Assuming the server returns the new document's ID
});
}catch(error){
console.log("error is", error);
dispatch({
type: 'POST_FAILURE',
payload: error.message,
});
}
};
// Classifieds loading
export const setClassifiedsLoading = () => {
return {
type: CLASSIFIEDS_LOADING,
};
};
这是classifiedsReducer.js
import {
CLASSIFIEDS_LOADING,
POST_SUCCESS,
POST_FAILURE
} from "../actions/classifiedsAction";
const initialState = {
loading: true,
postID:null,
error:null
};
export const ClassifiedsReducer = (state = initialState, action) => {
switch (action.type) {
case POST_SUCCESS:
return {
...state,
postId: action.payload,
loading: false,
};
case POST_FAILURE:
return {
...state,
error: action.payload,
loading: false,
};
case CLASSIFIEDS_LOADING:
return {
...state,
loading: true,
};
default:
return state;
}
};
您面临的问题可能是由于 dispatch(postClassifieds(newFormData)) 调用的 异步 性质造成的。异步 API 调用完成后,Redux 存储中的 postId 值会更新,但 console.log("postID is 2", postId) 和后续 navigate(/classifieds/${postId})在 Redux 状态更新之前执行,导致 postId 为 null。
为了解决这个问题,您可以利用 useEffect 钩子来监听 postId 中的变化,并在更新时触发导航。这是 PostClassified 组件的修改版本:
export const PostClassified = () => {
const postId = useSelector((state) => state.classifieds.postId);
useEffect(() => {
if (postId) {
console.log("postID is 2", postId);
navigate(`/classifieds/${postId}`);
}
}, [postId, navigate]);
const handleSubmit = async (e) => {
e.preventDefault();
setFormSubmitMessage(false);
newFormData.append("heading", formData.heading);
newFormData.append("category", formData.category);
await dispatch(postClassifieds(newFormData));
};
};
相关:溢出
这里的问题是提交处理程序在选定的
postId
状态上有一个陈旧的闭包。
更新代码,以便您的
postClassifieds
操作将解析值返回给可以等待的调用代码。
示例:
export const postClassifieds = (formData) => async(dispatch) => {
try {
const { data } = await axios.post('/posts', formData);
dispatch({
type: 'POST_SUCCESS',
payload: data._id,
});
return data._id; // <-- return postId to UI/calling code
} catch(error) {
console.log("error is", error);
dispatch({
type: 'POST_FAILURE',
payload: error.message,
});
throw error; // <-- re-throw error for UI/calling code
}
};
将异步逻辑包装在
try/catch
中以处理返回的 postId
值或任何抛出的错误或 Promise 拒绝。
const handleSubmit = async (e) => {
e.preventDefault();
try {
setFormSubmitMessage(false);
const newFormData = new FormData();
newFormData.append("heading", formData.heading);
newFormData.append("category", formData.category);
const postId = await dispatch(postClassifieds(newFormData));
// Success if we get this far 😀
console.log("postID is 2",postId);
navigate(`/classifieds/${postId}`);
} catch(error) {
// handle/ignore fetch failures/etc
}
};