React中Select标签特定选项值获取及Modal订单表单疑问
经纪商模拟器开发问题
我正在开发一款经纪商模拟器,有两个核心需求:
- 根据Select标签选择的不同货币对,获取对应的实时汇率值
- 不确定是否需要在Modal对话框中使用Form组件,将最终的订单信息发送到其他标签页
目前遇到的问题:尝试了多种值的传递方式都没解决,Modal对话框要么拿不到值,要么值不随选中的货币对变化,要么只显示某一个货币对的固定值。
初始代码
import React, {useState} from "react"; import './select.css' import Modal from "../popup/modal" import { useEffect } from "react"; const Select = () => { const [value, setValue] = useState(""); const [usdrub, setUsdrub] = useState(Math.random() * (64-61) + 61); useEffect(() => { const interval = setInterval(() => { setUsdrub(Math.random() * (64-61) + 61); }, 10000); return () => clearInterval(interval); }, []) const [rubusd, setRubusd] = useState(Math.random() * 2); useEffect(() => { const interval = setInterval(() => { setRubusd(Math.random() * 2); }, 10000); return () => clearInterval(interval); }, []) function changeSelect() { setValue(value) } const [modalActive, setModalActive] = useState(false) return ( <div> <select onChange={changeSelect}> <option name="USD/RUB" value={usdrub}>USD/RUB</option> <option name="RUB/USD" value={rubusd}>RUB/USD</option> </select> <div className="Curr"> <div className="Buy" name="buy"> <button className="Buy" type="btn" onClick={() => setModalActive(true)}>BUY {value + 1} </button> </div> <div className="Sell" name="sell"><button className="Sell" type="btn" onClick={() => setModalActive(true)}>SELL {value}</button></div> </div> <Modal active={modalActive} setActive={setModalActive} price={usdrub + 1}/> </div> ) } export default Select
更新后的代码
import React, {useState} from "react"; import './select.css' import Modalbuy from "../popup/Modalbuy" import Modalsell from "../popup/Modalsell" import { useEffect } from "react"; const Select = () => { const [value, setValue] = useState(""); const [usdrub, setUsdrub] = useState(Math.random() * (64-61) + 61); useEffect(() => { const interval = setInterval(() => { setUsdrub(Math.random() * (64-61) + 61); }, 10000); return () => clearInterval(interval); }, []) const [rubusd, setRubusd] = useState(Math.random() * 2); useEffect(() => { const interval = setInterval(() => { setRubusd(Math.random() * 2); }, 10000); return () => clearInterval(interval); }, []) function changeSelect(event) { setValue(event.target.value) } const [modalBuyActive, setModalBuyActive] = useState(false) const [modalSellActive, setModalSellActive] = useState(false) return ( <div> <select value = {value} onChange={changeSelect}> <option selected></option> <option name="USD/RUB" value={usdrub}>USD/RUB</option> <option name="RUB/USD" value={rubusd}>RUB/USD</option> </select> <div className="Curr"> <div className="Buy" name="buy"> <button className="Buy" type="btn" onClick={() => setModalBuyActive(true)}>BUY {value + 1} </button> </div> <div className="Sell" name="sell"><button className="Sell" type="btn" onClick={() => setModalSellActive(true)}>SELL {value}</button></div> </div> <Modalbuy active={modalBuyActive} setActive={setModalBuyActive} price={value + 1}/> <Modalsell active={modalSellActive} setActive={setModalSellActive} price={value}/> </div> ) } export default Select
相关组件代码
Modalbuy.js
import React from "react"; import "./modal.css"; const Modalbuy = ({active, setActive,price}) => { return ( <div className={active ? "modal active" : "modal"} onClick={() => setActive(false)}> <div className="modal__content" onClick={e => e.stopPropagation()}> <header>Make order</header> <p>BUY {price}</p> <input placeholder="Volume"></input> <div> <button>Ok</button> <button>Cancel</button> </div> </div> </div> ) } export default Modalbuy;
Modalsell.js
import React from "react"; import "./modal.css"; const Modalsell = ({active, setActive,price}) => { return ( <div className={active ? "modal active" : "modal"} onClick={() => setActive(false)}> <div className="modal__content" onClick={e => e.stopPropagation()}> <header>Make order</header> <p>SELL {price}</p> <input placeholder="Volume"></input> <div> <button>Ok</button> <button>Cancel</button> </div> </div> </div> ) } export default Modalsell;
Timer.js
import React from 'react'; import {useState, useEffect} from 'react' const Timer = () => { const [time, setTime] = useState(new Date().toLocaleTimeString()); useEffect(() => { const interval = setInterval(() => { setTime(new Date().toLocaleTimeString()); }, 1000); return () => clearInterval(interval); }, []); return ( <div className="clock"> {time} </div> ); }; export default Timer;
Trading.js
import React from "react"; import Timer from "./Timer"; import Select from "./select_curr/Select"; const Trading = () => { return ( <div> <Timer/> <Select/> </div> ) } export default Trading;
App.js
import './App.css'; import Page from './components/page/page' function App() { return ( <div className="App"> <Page/> </div> ); } export default App;
问题修复与优化方案
1. 汇率值同步问题修复
当前代码的核心问题:
- Select的option值是组件初始化时的固定值,当usdrub/rubusd定时更新时,option的value不会同步,导致选中后拿到的是旧汇率
value存储的是字符串类型的汇率,value + 1会变成字符串拼接(比如"62+1"变成"621"),而非数值计算
修改后的Select组件:
import React, { useState, useEffect } from "react"; import './select.css' import Modalbuy from "../popup/Modalbuy" import Modalsell from "../popup/Modalsell" const Select = () => { // 存储选中的货币对标识,而非直接存汇率值 const [selectedPair, setSelectedPair] = useState(""); const [usdrub, setUsdrub] = useState(Math.random() * (64-61) + 61); const [rubusd, setRubusd] = useState(Math.random() * 2); // 定时更新USD/RUB汇率 useEffect(() => { const interval = setInterval(() => { setUsdrub(Math.random() * (64-61) + 61); }, 10000); return () => clearInterval(interval); }, []) // 定时更新RUB/USD汇率 useEffect(() => { const interval = setInterval(() => { setRubusd(Math.random() * 2); }, 10000); return () => clearInterval(interval); }, []) // 获取当前选中货币对的实时汇率 const getCurrentRate = () => { switch(selectedPair) { case "USD/RUB": return usdrub; case "RUB/USD": return rubusd; default: return 0; } } // 处理货币对选择变化 function changeSelect(event) { setSelectedPair(event.target.value); } const [modalBuyActive, setModalBuyActive] = useState(false) const [modalSellActive, setModalSellActive] = useState(false) const currentRate = getCurrentRate(); return ( <div> <select value={selectedPair} onChange={changeSelect}> <option value="">请选择货币对</option> <option value="USD/RUB">USD/RUB</option> <option value="RUB/USD">RUB/USD</option> </select> <div className="Curr"> <div className="Buy"> <button className="Buy" onClick={() => setModalBuyActive(true)}> {/* 只在有选中值时显示价格,保留4位小数 */} BUY {currentRate > 0 ? (currentRate + 1).toFixed(4) : ""} </button> </div> <div className="Sell"> <button className="Sell" onClick={() => setModalSellActive(true)}> SELL {currentRate > 0 ? currentRate.toFixed(4) : ""} </button> </div> </div> {/* 传递实时汇率和货币对给Modal */} <Modalbuy active={modalBuyActive} setActive={setModalBuyActive} price={(currentRate + 1).toFixed(4)} pair={selectedPair}/> <Modalsell active={modalSellActive} setActive={setModalSellActive} price={currentRate.toFixed(4)} pair={selectedPair}/> </div> ) } export default Select
2. Modal中使用Form组件的建议
如果需要收集交易量等订单信息并发送到其他标签页,强烈建议使用Form组件,可以更规范地处理表单验证和数据提交。以Modalbuy为例修改:
import React, { useState } from "react"; import "./modal.css"; const Modalbuy = ({active, setActive, price, pair}) => { const [volume, setVolume] = useState(""); // 提交订单逻辑 const handleSubmit = (e) => { e.preventDefault(); // 验证交易量是否合法 if (!volume || isNaN(volume) || parseFloat(volume) <= 0) return; // 构造订单数据 const order = { type: "BUY", pair: pair, price: parseFloat(price), volume: parseFloat(volume), timestamp: new Date().toLocaleString() }; console.log("提交订单:", order); // 这里可以通过props回调、全局状态或跨标签通信方式传递订单 setActive(false); setVolume(""); } return ( <div className={active ? "modal active" : "modal"} onClick={() => setActive(false)}> <div className="modal__content" onClick={e => e.stopPropagation()}> <header>创建订单</header> <form onSubmit={handleSubmit}> <p>BUY {pair} @ {price}</p> <input type="number" placeholder="交易量" value={volume} onChange={(e) => setVolume(e.target.value)} min="0.01" step="0.01" required /> <div> <button type="submit">确认</button> <button type="button" onClick={() => setActive(false)}>取消</button> </div> </form> </div> </div> ) } export default Modalbuy;
3. 跨标签页传递订单信息的方案
如果需要将订单发送到其他标签页,可以选择以下几种方式:
- LocalStorage/SessionStorage:提交订单时将数据存入storage,其他标签页监听
storage事件获取新订单 - Broadcast Channel API:专门用于同源标签页之间的消息通信
- 全局状态管理:如果是单页应用的不同标签页组件,用React Context或Redux管理订单数据
以LocalStorage为例实现跨标签页通信:
在Modal的提交函数中添加:
const handleSubmit = (e) => { e.preventDefault(); if (!volume || isNaN(volume) || parseFloat(volume) <= 0) return; const order = { type: "BUY", pair: pair, price: parseFloat(price), volume: parseFloat(volume), timestamp: new Date().toLocaleString() }; // 将订单存入localStorage,触发其他标签页的storage事件 localStorage.setItem("newOrder", JSON.stringify(order)); setActive(false); setVolume(""); }
在接收订单的组件中添加监听:
import { useEffect, useState } from "react"; const OrderList = () => { const [orders, setOrders] = useState([]); useEffect(() => { const handleStorageChange = (e) => { if (e.key === "newOrder") { const newOrder = JSON.parse(e.newValue); setOrders(prev => [...prev, newOrder]); } } // 监听storage变化 window.addEventListener("storage", handleStorageChange); // 组件卸载时移除监听 return () => window.removeEventListener("storage", handleStorageChange); }, []); return ( <div className="order-list"> <h3>订单列表</h3> {orders.map((order, index) => ( <div key={index} className="order-item"> <p>{order.type} {order.pair} | 价格:{order.price} | 交易量:{order.volume} | 时间:{order.timestamp}</p> </div> ))} </div> ) } export default OrderList;
内容的提问来源于stack exchange,提问作者shvedd02
相关产品推荐
相关产品推荐

