UseSelector 值在反应中的handleSubmit 按钮内给出 null

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

我的代码流程是,用户填写表单并提交,然后转到调用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;
    }
  };
reactjs redux
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.