我的代码流是,用户填写表单并提交,然后转到调用API的操作,然后返回postId并将其存储在Reducer中.现在,我的主要Reaction组件有useSelector来获取postId的最新状态.因此,在调用操作并提交表单之后,我正在执行的导航到该POST的操作是'/classifieds/{postId}',但是postIdhandleSubmit函数内部显示为空,而在该函数外部显示的值为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;
  }
};

推荐答案

这里的问题是提交处理程序在所选的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
  }
};

Javascript相关问答推荐

在Angular中将样式应用于innerHTML

在react JS中映射数组对象的嵌套数据

使用Promise.All并发解决时,每个promise 的线性时间增加?

我创建了一个创建对象的函数,我希望从该函数创建的对象具有唯一的键.我怎么能做到这一点?

如何在Svelte中从一个codec函数中调用error()?

在使用REACT更改了CSS类之后,无法更改CSS样式

Rxjs流中生成IMMER不能在对象上操作

从另一个数组中的对应行/键值对更新数组中的键值对对象

搜索功能不是在分页的每一页上进行搜索

获取';无法解决导入和导入";slick-carousel/slick/slick-theme.css";';错误

我想将Sitecore搜索面过滤器从多个转换为单个

如何在Java脚本中对数据进行签名,并在PHP中验证签名?

更改agGRID/Reaction中的单元格格式

JavaScript&;Reaction-如何避免在不使用字典/对象的情况下出现地狱?

为什么在运行于<;img>;事件处理程序中的JavaScript中x和y是不可变的?

调用特定数组索引时,为什么类型脚本不判断未定义

KeyboardEvent:检测到键具有打印的表示形式

在对象的嵌套数组中添加两个属性

如何在css中裁剪成一定Angular 的圆的一部分,而不需要复杂的多边形

JS/css:将数字输入的S函数和可调整大小的元素S函数绑定在一起