React?中使用状态的DRY原理



我正在学习如何做出反应,并试图了解创建多个useStates的最佳实践,这些useStates基本上做着相同的事情,只是代码中的项目不同。

例如,我的代码如下:

import { Button, Typography } from '@mui/material';
import { Box } from '@mui/system';
import React, {useState} from 'react';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select from '@mui/material/Select';
export default MenuPage(){

const menuItems = [
{
name: 'Americano',
price: 1.50,
},
{
name: 'Espresso',
price: 3.50,
},
{
name: 'Macchiato',
price: 5.50,
},
{
name: 'Cafe Mocha',
price: 8.50,
},
{
name: 'Latte',
price: 6.50,
},
{
name: 'Cappucino',
price: 5.50,
},
{
name: 'Frappe',
price: 8.50,
},
];
//*********************************************
// code that needs to be changed here instead of creaing n many useStates for n many items in menuItems list.
const [order, setOrder] = useState('');
const handleChange = (event) => {
setOrder(event.target.value);
};
//*********************************************
return(
{menuItems.map((item) => {
return (
<Box display='flex' flexDirection='row' alignItems='center' justifyContent='center' textAlign='center' borderBottom='0.5px solid black' sx={{ my: 10, mx: 10 }}>
<Box flex={1} textAlign='center' sx={{ fontSize: '35px', }}>
{item.name}:
</Box>
<br />
<Box flex={1} textAlign='center' sx={{ fontSize: '25px' }}>
${item.price}0
</Box>
<Box flex={0.5} textAlign='center'>
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">Order</InputLabel>
<Select
value={order}
label="Order"
onChange={handleChange}>
<MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={3}>3</MenuItem>
</Select>
</FormControl>
</Box>
</Box>
);
})}
);
}

所以我的问题是,与其创建n个const [nthOrder, setNthOrder] = useState(''),不如为每个订单创建尽可能多的useStates的最佳方法是什么?我知道我们不能在回调或forloops中运行useState。

感谢您提前提供的帮助。

如果希望多个订单处于同一状态,可以将状态设置为数组,并将订单添加到数组中。

const [order, setOrder] = useState(['']);
const handleChange = (event) => {
setOrder(prevState => { return [...prevState, event.target.value]});
};

在这个例子中,你可以看到我使用排列运算符返回一个新的数组,其中包含以前的值加上新的值,这样你就可以避免重复。

我的解决方案是将menuItems作为组件的状态进行维护。将order字段添加到每个菜单项中。将状态及其CRUD逻辑放入一个自定义挂钩中,保持组件干净。

import React, { useState } from 'react';
function useMenuItems() {
const [menuItems, setMenuItems] = useState([
{ name: 'Americano', price: 1.5, order: '' },
{ name: 'Espresso', price: 3.5, order: '' },
{ name: 'Macchiato', price: 5.5, order: '' },
{ name: 'Cafe Mocha', price: 8.5, order: '' },
{ name: 'Latte', price: 6.5, order: '' },
{ name: 'Cappucino', price: 5.5, order: '' },
{ name: 'Frappe', price: 8.5, order: '' },
]);
const setOrderForMenuItem = (nOrder, itemName) => {
setMenuItems((pre) => {
return pre.map((v) => (v.name === itemName ? { ...v, order: nOrder } : v));
});
};
return { menuItems, setOrderForMenuItem } as const;
}
export default function MenuPage() {
const { menuItems, setOrderForMenuItem } = useMenuItems();
const handleChange = (event, item) => {
setOrderForMenuItem(event.target.value, item.name);
};
return (
<div>
{menuItems.map((item, i) => {
return (
<select
data-testid={`menu-order-${i}`}
key={item.name}
value={item.order}
onChange={(e) => handleChange(e, item)}
>
<option value={1}>1</option>
<option value={2}>2</option>
<option value={3}>3</option>
</select>
);
})}
</div>
);
}

最新更新