React向Messages组件传ID对接Flask接口的问题修复
问题描述
我是React开发新手,尝试从Matches.js向Messages.js传递id和user_id,Messages组件需与Flask后端配合使用,但加载时user_id返回undefined。需要修改代码,使id包含在URL中(如http://localhost:5000/messages/6442d4b8e188665ed2268783),同时将user_id(如6442d4b8e188665ed2268784)作为数据发送。
以下是原代码及修改方案:
原代码
Matches.js
import { useState } from "react"; import axios from "axios"; import { useNavigate, useParams } from "react-router-dom"; import "./matches.css"; function Matches() { const [userId, setUserId] = useState(""); // userId is the user's id that they enter const [matches, setMatches] = useState([]); const navigate = useNavigate(); const { id } = useParams(); // id is the user's id that is passed in from the url const handleSubmit = async (e) => { e.preventDefault(); try { const res = await axios.get(`http://localhost:5000/matches/${userId}`); const matchesWithIds = res.data; setMatches(matchesWithIds); } catch (error) { console.error(error.response.data); } }; const handleInputChange = (e) => { setUserId(e.target.value); }; const getMessagesWithUser = (matchId) => { navigate(`/messages/${userId}`, { state: { id: id, user_id: matchId } }); }; return ( <div> <h1>Get Matches</h1> <form onSubmit={handleSubmit}> <label> User ID: <input type="text" value={userId} onChange={handleInputChange} /> </label> <button type="submit">Submit</button> </form> {matches.length > 0 && ( <div> <h2>Matches:</h2> <ul> {matches.map((match) => ( <li key={match} className="match-card" onClick={() => getMessagesWithUser(match)} > {match} </li> ))} </ul> </div> )} </div> ); } export default Matches;
Messages.js
import { useEffect, useState } from "react"; import axios from "axios"; import { useLocation } from "react-router-dom"; function Messages({ id, user_id }) { const [messages, setMessages] = useState([]); const [messageInput, setMessageInput] = useState(""); const location = useLocation(); const userId = location.state.user_id; useEffect(() => { const getMessages = async () => { try { const res = await axios.get(`http://localhost:5000/messages/${id}`, { params: { user_id: user_id }, }); setMessages(res.data); } catch (error) { console.error(error.response.data); } }; getMessages(); }, [id, user_id]); const handleMessageInput = (e) => { setMessageInput(e.target.value); }; const sendMessage = async (e) => { e.preventDefault(); try { const res = await axios.post(`http://localhost:5000/messages`, { sender_id: location.state.id, recipient_id: location.state.user_id, message: messageInput, }); setMessages((prevMessages) => [...prevMessages, res.data]); setMessageInput(""); } catch (error) { console.error(error.response.data); } }; return ( <div> <h1>Messages</h1> <h2>Conversation with user {user_id}</h2> <ul> {messages.map((message) => ( <li key={message._id}> {message.sender_id}: {message.message} </li> ))} </ul> <form onSubmit={sendMessage}> <label> Message: <input type="text" value={messageInput} onChange={handleMessageInput} /> </label> <button type="submit">Send</button> </form> </div> ); } export default Messages;
App.js
import React, { useState } from "react"; import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; import Login from "./login/login.js"; import Matches from "./matches.js"; import Home from "./home/home.js"; import Messages from "./messages.js"; function App() { const [userId, setUserId] = useState(""); return ( <Router> <Routes> <Route path="/login" element={<Login setUserId={setUserId} />} /> <Route path="/matches" element={<Matches userId={userId} />} /> <Route path="/home" element={<Home userId={userId} />} /> <Route path="/messages/:id" element={<Messages />} /> </Routes> </Router> ); } export default App;
Flask后端代码
#get messages with a user @app.route('/messages/<string:id>', methods=['GET']) def get_messages_with_user(id): required_fields = ["user_id"] if all(field in request.form for field in required_fields): new_user = { "user_id" : request.form["user_id"] } all_messages = messages_collection.find({ "$or": [ {"sender_id": id, "recipient_id": new_user['user_id']}, {"recipient_id": id, "sender_id": new_user['user_id']}, ] }) message_list = [] for msg in all_messages: # Convert ObjectId fields to strings msg['_id'] = str(msg['_id']) msg['sender_id'] = str(msg['sender_id']) msg['recipient_id'] = str(msg['recipient_id']) message_list.append(msg) return jsonify(message_list)
修改方案
1. 调整Matches.js的跳转逻辑
将当前用户的id放入URL,匹配用户的user_id通过路由state传递:
import { useState } from "react"; import axios from "axios"; import { useNavigate, useParams } from "react-router-dom"; import "./matches.css"; function Matches() { const [userId, setUserId] = useState(""); // 用户输入的ID const [matches, setMatches] = useState([]); const navigate = useNavigate(); const { id } = useParams(); // 当前用户的ID,来自URL const handleSubmit = async (e) => { e.preventDefault(); try { const res = await axios.get(`http://localhost:5000/matches/${userId}`); const matchesWithIds = res.data; setMatches(matchesWithIds); } catch (error) { console.error(error.response.data); } }; const handleInputChange = (e) => { setUserId(e.target.value); }; // 修改跳转:URL携带当前用户id,state传递匹配用户的user_id const getMessagesWithUser = (matchId) => { navigate(`/messages/${id}`, { state: { user_id: matchId } }); }; return ( <div> <h1>获取匹配用户</h1> <form onSubmit={handleSubmit}> <label> 用户ID: <input type="text" value={userId} onChange={handleInputChange} /> </label> <button type="submit">提交</button> </form> {matches.length > 0 && ( <div> <h2>匹配用户:</h2> <ul> {matches.map((match) => ( <li key={match} className="match-card" onClick={() => getMessagesWithUser(match)} > {match} </li> ))} </ul> </div> )} </div> ); } export default Matches;
2. 修复Messages.js的参数获取与请求逻辑
使用useParams获取URL中的id,添加空值检查避免undefined:
import { useEffect, useState } from "react"; import axios from "axios"; import { useLocation, useParams } from "react-router-dom"; function Messages() { const [messages, setMessages] = useState([]); const [messageInput, setMessageInput] = useState(""); const location = useLocation(); const { id } = useParams(); // 从URL获取当前用户id const userId = location.state?.user_id; // 可选链避免state不存在报错 useEffect(() => { if (!userId) return; const getMessages = async () => { try { const res = await axios.get(`http://localhost:5000/messages/${id}`, { params: { user_id: userId }, }); setMessages(res.data); } catch (error) { console.error(error.response.data); } }; getMessages(); }, [id, userId]); const handleMessageInput = (e) => { setMessageInput(e.target.value); }; const sendMessage = async (e) => { e.preventDefault(); if (!userId) return; try { const res = await axios.post(`http://localhost:5000/messages`, { sender_id: id, recipient_id: userId, message: messageInput, }); setMessages((prevMessages) => [...prevMessages, res.data]); setMessageInput(""); } catch (error) { console.error(error.response.data); } }; return ( <div> <h1>消息</h1> <h2>与用户 {userId || "未知"} 的对话</h2> <ul> {messages.map((message) => ( <li key={message._id}> {message.sender_id}: {message.message} </li> ))} </ul> <form onSubmit={sendMessage}> <label> 消息: <input type="text" value={messageInput} onChange={handleMessageInput} /> </label> <button type="submit" disabled={!userId}>发送</button> </form> </div> ); } export default Messages;
3. 修正Flask后端的参数获取方式
GET请求使用request.args获取查询参数,添加参数缺失的错误处理:
# 获取与某用户的对话消息 @app.route('/messages/<string:id>', methods=['GET']) def get_messages_with_user(id): user_id = request.args.get('user_id') # 检查user_id是否存在 if not user_id: return jsonify({"error": "user_id参数缺失"}), 400 all_messages = messages_collection.find({ "$or": [ {"sender_id": id, "recipient_id": user_id}, {"recipient_id": id, "sender_id": user_id}, ] }) message_list = [] for msg in all_messages: # 将ObjectId转换为字符串 msg['_id'] = str(msg['_id']) msg['sender_id'] = str(msg['sender_id']) msg['recipient_id'] = str(msg['recipient_id']) message_list.append(msg) return jsonify(message_list)
修改说明
- 参数传递:当前用户
id通过URL公开传递,匹配用户user_id通过路由state隐式传递,符合需求的URL格式。 - 错误防护:添加了
userId空值检查,避免未定义时发送无效请求或渲染错误内容。 - 请求规范:GET请求参数通过
params传递,后端使用request.args获取,符合HTTP协议规范。
内容的提问来源于stack exchange,提问作者Scott Ruddy
相关产品推荐
相关产品推荐

