当我使用Form.Select
时,从useState产品获取price
值时遇到一些问题。
其思想是,使用Form.Select
,您可以通过产品名称选择产品,然后onChangeProduct
将使用给定的产品名称和该产品的price属性设置data
的状态。我只是不确定如何获取price
值,而无需用户在Form.Select
中手动选择价格。
该代码是一个简单的说明代码,我得到了这么票价.
如果你有任何组件,将使这比我很高兴听到它更容易。
希望你能理解。
const [data, setData] = useState([]);
const [product, setProduct] = useState([
{ name: "TV", price: 1000 },
{ name: "Phone", price: 3000 },
]);
const onChangeProduct = (name, value) => {
setData((prevValue) => {
const newValues = [...prevValues];
newValues = Object.assign({}, newValues, {[name]: value });
return newValues;
});
};
return (
<Form>
<Form.Select
onChange={(event) => {onChangeProduct("name", event.target.value);}}
value={product.name}
name="product"
>
{product.map((item) => {
return <option value={item.name}>{item.name}</option>;
})}
</Form.Select>
</Form>
);
- 编辑**
我决定用另一种方法来实现这一点,我可能需要将产品设置为一个数组/状态,因为我希望稍后能够同时获取价格和产品。
这个想法是使系统工作与添加/删除产品到一张卡,你将能够检查与产品名称和价格结帐。因此,你能够选择一个产品列表,并以这种方式看到该产品的价格属性。
我使用的函数与此处获得的函数相同:onChange, onProductRemove and add function
卡片表单. jsx-〉模态编辑产品. jsx-〉产品编辑. jsx
在CardForm.jsx
中,我检查是否有ID,如果有,我将获取该用户已经选择的所有产品。
CardForm.jsx
const CardForm = () => {
const [data, setData] = useState({});
const { id } = useParams();
const [products, setProducts] = useState([]);
useEffect(() => {
if (id) {
const fetchData = async () => {
const docRef = doc(db, "user", id);
try {
const docSnap = await getDoc(docRef);
setData(docSnap.data());
} catch (error) {
console.log(error);
}
};
fetchData().catch(console.error);
}
}, []);
const handleProductChanged = (product) => {
setData((data) => ({ ...data, product }));
};
return (
<>
<Container className="mb-3 content_container_primary">
<Row>
<Col xs={12} md={12} lg={8} className="">
<Form>
<div className="box content_pa">
<Col xs={12} md={12} lg={12}>
<div>
<ModalEditProducts
onProductChanged={handleProductChanged}
data={data.product ?? []}
title="Edit products"
/>
</div>
</Col>
</div>
</Form>
</Col>
</Row>
</Container>
</>
);
};
ModalEditProducts.jsx
const ModalEditProducts = ({ title, data, onProductChanged }) => {
const [show, setShow] = useState(false);
const [newData, setNewData] = useState([]);
useEffect(() => {
setNewData(data);
}, [data, show]);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const handleProductChange = (index, name, value) => {
setNewData((prevValues) => {
const newValues = [...prevValues];
newValues[index] = Object.assign({}, newValues[index], { [name]: value });
return newValues;
});
};
const handleProductAdded = () => {
setNewData((prevValues) => [...prevValues, { product: "", price: 0 }]);
};
const handleProductRemoved = (index) => {
setNewData((prevValues) => {
const newValues = [...prevValues];
newValues.splice(index, 1);
return newValues;
});
};
const handleSubmitProducts = (e) => {
e.preventDefault();
onProductChanged(newData);
setShow(false);
};
return (
<>
<div className="content_header">
<div className="content_header_top">
<div className="header_left">Products</div>
<div className="header_right">
<Button className="round-btn" onClick={handleShow}>
<i className="fa-solid fa-pencil t-14"></i>
</Button>
</div>
</div>
</div>
{show && (
<Modal show={show} onHide={handleClose} size="">
<Modal.Header closeButton>
<Modal.Title>{title}</Modal.Title>
</Modal.Header>
<Modal.Body>
<ProductEdit
data={newData}
onProductChanged={handleProductChange}
onProductAdded={handleProductAdded}
onProductRemoved={handleProductRemoved}
/>
</Modal.Body>
<Modal.Footer>
<Form>
<Button
className="btn-skill-complete"
onClick={handleSubmitProducts}
>
Save
</Button>
</Form>
</Modal.Footer>
</Modal>
)}
</>
);
};
ProductEdit.jsx
const ProductEdit = ({ data, onProductChanged, onProductRemoved, onProductAdded }) => {
const [products, setProducts] = useState([]);
useEffect(() => {
GetProducts(setProducts);
});
return (
{data.length > 0 ? (
<Row>
<Col xs={9} md={9}>
<div className="product-modal-title mb-3">Pick a new product</div>
</Col>
<Col xs={3} md={3}>
<div className="product-modal-title mb-3 text-center">
Remove/add
</div>
</Col>
</Row>
) : null}
{data.length === 0 ? (
<Col xs={12} md={12}>
<Button
className="btn-st-large t-16 "
type="button"
onClick={onProductAdded}
>
Add a product
</Button>
</Col>
) : (
<>
{data?.map((inputField, index) => (
<div key={index}>
<Row>
<Col xs={9} md={9}>
<Form.Select
as={Col}
className="mb-3"
onChange={(event) => {
onProductChanged(index, "product", event.target.value);
}}
id="product"
name="product"
value={inputField.product}
>
<option>Choose product</option>
{products.map((item) => {
return (
<option key={item.id} value={item.name}>
{item.name} ({item.price} kr.)
</option>
);
})}
</Form.Select>
</Col>
<Col xs={3} md={3}>
<div className="btn-section">
<button
type="button"
className="round-btn"
onClick={onProductAdded}
>
<i className="fa-solid fa-plus"></i>
</button>
<button
type="button"
className="round-btn"
onClick={() => onProductRemoved(index)}
>
<i className="fa-solid fa-minus"></i>
</button>
</div>
</Col>
</Row>
</div>
))}
</>
)}
</Form>
);
};
1条答案
按热度按时间bhmjp9jg1#
首先,产品看起来是静态的,永远不会改变。因此不需要保持它们的状态,因为永远不需要改变它们。你只需要在某个时候改变一些东西。你可以把它们放在组件之外并引用它们。性能上的微小改进,但也向其他看你代码的人发出信号,它们是不可改变的和静态的。
第二,修改处理程序过于复杂,这里你存储的不是一个对象数组,而是一个简单的选择值(所选项的名称)。React Bootstrap只在
event
中传递选项的value
,而不是整个对象。由于该值只是一个普通字符串,在JS中被视为“原语”,你不需要担心任何不可变的状态改变,当你把字符串传递给函数时,它们被复制了,但是如果你只有名字,怎么得到价格呢?为了得到价格,你可以使用这个名字来查找相关的选项,并得到价格属性。find是一个很有用的工具,它允许你根据你定义的一些真实性来查找数组中的单个项。
您在问题中建议也将价格存储在状态中;你可能会奇怪我为什么不这样做,实际上在这里你没有选择,因为库只给你
option
的value
,但是其他库会给你整个选项,但是一般来说,只存储最小值来标识源数据中的选择更好,因为您避免了一系列与保持项与源数据同步有关的错误。在这里,你的期权数据在哪里没有改变并不重要,但这只是一个很好的实践,最好使用唯一的标识符在规范的源数据中查找它。我还添加了一个默认的“请选择”选项。默认状态首先选择这个(空字符串)
注意:在用户选择选项之前,
price
将为undefined
,因为默认的""
选项不会出现在products
中。如果find
遍历数组,并且根据传递的条件,它所循环的项都不真实,则find
返回undefined。这就是为什么我在访问price时在find之后使用
?
(optional chaining),否则会得到一个错误。