You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React组件状态数据传递至Node.js服务器报错求助

问题描述

我尝试将React组件state中存储的emailUserInput数据发送至Node.js服务器的server.js文件,但服务器终端出现错误:

cannot read properties of undefined (reading 'emailUserInput')

同时客户端浏览器控制台显示请求因状态码500失败(ERR_BAD_RESPONSE),查看object.config发现数据已在data键中传递。请问是数据传递方式存在问题还是服务器本身的问题?


服务器端代码(server.js)
const express = require("express"); //needed to launch server
const cors = require("cors"); //needed to disable sendgrid security
const app = express(); //alias from the express function
app.use(cors());

const hostname = "server";
const port = 4000;

var corsOptions = {
  origin: 'http://localhost:3000',
  optionsSuccessStatus: 200 
}

app.post("/", cors(corsOptions), (req, res) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  const emailInfo = req.body.emailUserInput;
  console.log(emailInfo);
  res.json(emailInfo);

  // sendgrid details //

  require("dotenv").config();
  const sgMail = require("@sendgrid/mail");
  const apikey = process.env.SENDGRID_API_KEY;
  sgMail.setApiKey(apikey);
  const msg = {
    to: emailInfo,
    from: "email",
    subject: "Congratulations! Your event link has been created!",
    text: `Here is your event link:`,
    html: "<strong>and easy to do anywhere, even with Node.js</strong>",
  };

  // email sending logic //

  //ES8
  (async () => {
    try {
      await sgMail.send(msg);
    } catch (error) {
      console.error(error);

      if (error.response) {
        console.error(error.response.body);
      }
    }
  })();
});

app.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

React组件代码
import "../StyleComponents/CreateEvent.css";
import { useState } from 'react';
import { db } from '../firebase';
import { uid } from "uid";
import { set, ref } from "firebase/database";
import Header from "./Header";
import { useNavigate } from 'react-router-dom';
import { getStorage, ref as sref, uploadBytes } from "firebase/storage";
import PlacesAutocomplete from 'react-places-autocomplete';
import { geocodeByAddress, getLatLng } from 'react-places-autocomplete';
import axios from 'axios';

function CreateEvent() {

    // store user inputs in state //

    const [titleUserInput, setTitleUserInput] = useState('');
    const [dateUserInput, setDateUserInput] = useState('');
    const [timeUserInput, setTimeUserInput] = useState('');
    const [address, setAddress] = useState('');
    const [setCoordinates] = useState({
        lat: null,
        lng: null,
    })
    const [headerUserInput, setHeaderUserInput] = useState('');
    const [detailsUserInput, setDetailsUserInput] = useState('');
    const [lengthUserInput, setLengthUserInput] = useState('');
    const [emailUserInput, setEmailUserInput] = useState('');
    const [userSubmit, setUserSubmit] = useState('');
    const [error, setError] = useState(false);

    // Create a root reference for storing event photos //

    const storage = getStorage();

    // handle changing user input data //

    const handleTitleChange = (e) => {
        setTitleUserInput(e.target.value);
    }
    const handleDateChange = (e) => {
        setDateUserInput(e.target.value);
    }
    const handleTimeChange = (e) => {
        setTimeUserInput(e.target.value);
    }

    const handleSelect = async (value) => {
        const results = await geocodeByAddress(value);
        const latLng = await getLatLng(results[0]);
        setAddress(value);
        setCoordinates(latLng);
    }

    const handleDetailsChange = (e) => {
        setDetailsUserInput(e.target.value);
    }
    const handleLengthChange = (e) => {
        setLengthUserInput(e.target.value);
    }
    const handleHeaderChange = (e) => {
        // Create a root reference for storing event photos //
        setHeaderUserInput(e.target.files[0]);
    }

    const handleEmailChange = (e) => {
        setEmailUserInput(e.target.value);
    }

    const navigate = useNavigate();

       // make call to the backend database to send email user input data //

    const serverUrl = 'http://localhost:4000';

    // submit user data to database with unique ID for each event //

    const writeToDataBase = () => {
        let uuid = uid()
        if (titleUserInput.length === 0 || dateUserInput.length === 0 || timeUserInput.length === 0 || address.length === 0 || emailUserInput.length === 0) {
            setError(true);
        }
        if (titleUserInput && dateUserInput && timeUserInput && address && emailUserInput) {
            const storageRef = sref(storage, uuid);
            set(ref(db, `/${uuid}`), {
                EventPhoto: headerUserInput,
                EventTitle: titleUserInput,
                EventDate: dateUserInput,
                EventTime: timeUserInput,
                EventLength: lengthUserInput,
                EventLocation: address,
                EventDetails: detailsUserInput,
            });
            const getEmailInput = () => {
        axios.post(serverUrl, emailUserInput).then((res) => {
            console.log(res);
        }).catch(console.log('error'));
        }
            getEmailInput('');
            setUserSubmit('');
            uploadBytes(storageRef, headerUserInput).then(() => {
                navigate(`/EventCreated/${uuid}`);
            });
        }
    }
  
    return (
           <>
            < Header />
    <div className="event-creation-container">
            <h1>Create a New Event</h1>
                <form>
            <div className="event-name-container event-input">
        <label for="eventTitle">Name of Event<span>*</span></label>
                        <input type="text" id="EventTitle" value={titleUserInput} onChange={handleTitleChange} /> 
                        {error && titleUserInput === '' ?
                            <label id="form-validation-label">Event name must be filled</label> : ""}
                    </div>
                    <div className="date-time-length">
            <div className="date-input-container event-input">      
                <label for="Date">Date<span>*</span></label>
                            <input type="date" id="EventDate" value={dateUserInput} onChange={handleDateChange} />   
                            {error && dateUserInput === '' ? <label id="form-validation-label">Event date must be filled</label>: ""}
                    </div>    
            <div className="time-input-container event-input">       
                <label for="Time">Time<span>*</span></label>
                <input id="EventTime" type="time" name="time" timezone="timezone" value={timeUserInput} onChange={handleTimeChange} /> 
                        </div>
                        {error && timeUserInput === '' ? <label id="form-validation-label">Event time must be filled</label> : ""}
                    <div className="length-input-container event-input">
                        <label for="Length">Length</label>
                        <input id="EventLength" type="text" value={lengthUserInput} onChange={handleLengthChange} />
                        </div>
                    </div>
            <div className="location-input-container event-input">
                        <label for="Location">Location<span>*</span></label>
                        <PlacesAutocomplete onChange={setAddress} value={address} onSelect={handleSelect}
                        >
                            {({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (       
                                <div>
                                    <input id="EventLocation" {...getInputProps()} />
                                    <div className="location-suggestions">
                                        {loading ? <div>...loading</div> : null}
                                        {suggestions.map((suggestion) => {
                                            const style = {
                                                backgroundColor: suggestion.active ? "#41b6e6" : "#fff"
                                            };
                                            return <div {...getSuggestionItemProps(suggestion, { style })}>{suggestion.description}</div>
                                        })}
                                    </div>
                                </div>
                            )}
                            </PlacesAutocomplete>
                    </div> 
                    {error && address ==='' ? <label id="form-validation-label">Event location must be filled</label> : ""}
            <div className="details-input-container event-input">
        <label for="Event_Details">Event Details</label>
                    <textarea type="text" id="EventDetails" value={detailsUserInput} onChange={handleDetailsChange} />
                    </div>
                    <div className="header-input-container event-input">
             <div className="upload-image-flex-container">
        <label for="header_image">Upload Header Image  (optional)</label>
                        <input className="upload-input" type="file" id="
                        EventImage" name="filename" accept="image/png, image/jpeg" onChange={handleHeaderChange} />
                        </div>
                    </div>
                    <div className="orangizer-email-container">
                        <label for="organizer-email">Organizer's Email<span>*</span></label>
                        <p>The event page link will be sent to your email</p>
                        <input id="EventEmail" type="email" name="email" value={emailUserInput} onChange={handleEmailChange} />
                        {error && emailUserInput === '' ? <label id="form-validation-label">Event organizer's email must be entered</label> : ""}
            </div>
                <div className="create-event-btn-container">
                        <button className="event-create-button" type="button" value={userSubmit} onClick={writeToDataBase}>Create Event</button>
                </div>
        </form>  
    </div>
</>
)}

export default CreateEvent;

问题原因及解决方法

1. 服务器端核心问题:缺少JSON请求体解析中间件

Express默认不会自动解析JSON格式的请求体,导致req.body为undefined,读取emailUserInput时触发报错。
解决步骤:
在app.use(cors())之后添加以下代码:

app.use(express.json());

2. 客户端数据格式不匹配

当前React代码中,axios.post直接发送字符串类型的emailUserInput,但服务器期望从req.body.emailUserInput读取属性值,需要将请求数据包装为对象。
解决步骤:
修改React中的axios.post调用:

axios.post(serverUrl, { emailUserInput: emailUserInput })
// 或使用ES6简写:
axios.post(serverUrl, { emailUserInput })

3. 可选优化点

  • 将require("dotenv").config()和const sgMail = require("@sendgrid/mail")移到文件顶部,避免在每个请求中重复加载模块。
  • 调整邮件发送逻辑的位置,确保响应客户端前完成邮件发送(或使用await处理异步操作),避免提前响应导致的潜在问题。

内容的提问来源于stack exchange,提问作者DannyMac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 17:48:08