React 中的handleSubmit 按钮中useSelector 值仍然为空

问题描述 投票:0回答:2

我的代码流程是,用户填写表单并提交,然后执行调用 API 的操作,然后返回

postId
并将其存储在减速器中。现在我的主要 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;
  }
};
javascript reactjs redux redux-thunk
2个回答
0
投票

您面临的问题可能是由于 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));
  };

};

相关:溢出


0
投票

这里的问题是提交处理程序在选定的

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
  }
};
© www.soinside.com 2019 - 2024. All rights reserved.