arrays - 反应插入/删除数组中的行问题未更新
问题描述
需要建议。我有一个基本的父 (AddressList) 和子 (Address) 组件层次结构。添加删除按钮位于地址组件中。
我的问题是,当用户选择下拉菜单和文本字段时,值会更新,但是如何更新 Parent 组件中的数组?当我按 + 按钮添加新行时,数组不会更新显示填充字段的行。所有行都返回到它们的初始状态。
我尝试使用 useReducer() 但我得到了相同的结果。
想法?
const AddressList = (props) => {
const [addresses, setAddresses] = React.useState(props.addresses);
const handleAddRow = () => {
let rows = [...addresses];
rows.push(AddressModel);
setAddresses(rows);
};
const handleRemoveRow = (index) => {
let rows = [...addresses];
rows.splice(index, 1);
setAddresses(rows);
};
return (
<React.Fragment>
{ addresses.map((address, index) =>
<Address
index={index}
item={address}
key={Math.random()}
handleAddRow={handleAddRow}
handleRemoveRow={handleRemoveRow}/>
)}
</React.Fragment>
);
};
export default AddressList;
const useStyles = makeStyles(theme => ({
button: {
margin: theme.spacing(1),
},
root: {
display: 'inline-flex',
maxWidth: 800,
minWidth: 300,
padding: 10,
width: '100%'
}
}));
const types = ['Home', 'Work'];
const Address = (props) => {
const classes = useStyles();
// const [address, setAddress] = React.useState(props.item);
const [address, setAddress] = useReducer((myArray, { type, value }) => {
switch (type) {
case "add":
return [...myArray, value];
case "remove":
return myArray.filter((_, index) => index !== value);
default:
return myArray;
}
}, [address]);
const handleAddressChange = name => event => {
setAddress({ ...address, [name]: event.target.value });
};
const index = props.index;
const handleAddRow = props.handleAddRow;
const handleRemoveRow = props.handleRemoveRow;
return (
<Grid container className={classes.root} spacing={3}>
<Grid item xs={12} sm={2}>
<TextField
id="type"
label="Email Type"
margin="normal"
value={address.type}
onChange={handleAddressChange('type')}
fullWidth
select>
{types.map(option => (
<MenuItem key={option} value={option}>{option}</MenuItem>
))}
</TextField>
</Grid>
<Grid item xs={12} sm={9}>
<TextField
id="address"
label="Address"
margin="normal"
value={address.address}
onChange={handleAddressChange('address')}
fullWidth
required/>
</Grid>
<Grid item xs={12} sm={1}>
{
index === 0 ?
<IconButton className={classes.button} aria-label="add" onClick={() => handleAddRow()}>
<AddIcon/>
</IconButton>
:
<IconButton className={classes.button} aria-label="delete" onClick={() => handleRemoveRow(index)}>
<DeleteIcon/>
</IconButton>
}
</Grid>
</Grid>
);
};
export default Address;
export const AddressModel = {
id: 0,
type: 'Home',
address: ''
};
解决方案
主要更改是首先更新您的地址模型,以便每个项目都有一个id
而不是依赖于索引。
const addresses = [
{ id: 0, address: "home address 1", type: "Home" },
{ id: 1, address: "home address 2", type: "Home" },
{ id: 2, address: "work address 1", type: "Work" }
];
...然后将您的地址的更新代码移动到父级。所以你只在一个地方拥有你的状态,你在那里处理所有的更新。
所以你AddressList
现在看起来像这样:
const AddressList = props => {
const [addresses, setAddresses] = React.useState(props.addresses);
const handleAddRow = () => {
setAddresses([
...addresses,
{ id: addresses.length, address: "new address", type: "Home" }
]);
};
const handleRemoveRow = id => {
const rows = addresses.filter(address => address.id !== id);
setAddresses(rows);
};
const updateAddress = (id, ev) => {
const rows = addresses.map(item =>
item.id === id ? { ...item, address: ev.target.value } : item
);
setAddresses(rows);
};
const updateType = (id, ev) => {
const rows = addresses.map(item =>
item.id === id ? { ...item, type: ev.target.value } : item
);
setAddresses(rows);
};
return (
<React.Fragment>
{addresses.map((address, index) => (
<Address
index={index}
item={address}
key={address.id}
handleAddRow={handleAddRow}
handleRemoveRow={handleRemoveRow}
updateType={updateType}
updateAddress={updateAddress}
/>
))}
</React.Fragment>
);
};
还有你的地址:
const Address = props => {
const {
updateType,
updateAddress,
item,
index,
handleAddRow,
handleRemoveRow
} = props;
return (
<Grid container spacing={3}>
<Grid item xs={12} sm={2}>
<TextField
id="type"
label="Email Type"
margin="normal"
value={item.type}
onChange={ev => updateType(item.id, ev)}
fullWidth
select
>
{types.map(option => (
<MenuItem key={option} value={option}>
{option}
</MenuItem>
))}
</TextField>
</Grid>
<Grid item xs={12} sm={9}>
<TextField
id="address"
label="Address"
margin="normal"
value={item.address}
onChange={ev => updateAddress(item.id, ev)}
fullWidth
required
/>
</Grid>
<Grid item xs={12} sm={1}>
{index === 0 ? (
<IconButton aria-label="add" onClick={handleAddRow}>
Add
</IconButton>
) : (
<IconButton
aria-label="delete"
onClick={() => handleRemoveRow(item.id)}
>
Remove
</IconButton>
)}
</Grid>
</Grid>
);
};
推荐阅读
- python - 将数字标签分配给图形时出错
- c++ - 根据结构成员数据从向量返回结构项的函数
- regex - 如何在 Perl 脚本中的正则表达式搜索后追加
- java - 为什么我的 swapChildren() 函数只能部分工作?
- ios - 我无法导入我需要的东西来使用 MaterialContainerScheme
- python - 相互环绕的递归彩虹色圆圈
- excel - 如何使用 COUNTIF,使其依赖于过滤器和数据透视表?
- python - 将多个文件中的 json 对象逐行合并到一个文件中
- mask - 如何使用来自掩码字段(文本)的图标创建 HMENU/TMENU?
- unity3d - 重命名文件夹后Unity中的空引用异常