javascript - React - map 函数仅使用数组中的最后一项设置输入值
问题描述
我有这个带有输入字段的 RenamePopover 组件,我在位于 Board 组件中的 map 函数中使用它。当我遍历数组时,我将“board.name”作为 value 属性传递给 RenamePopover,这样最后,每个渲染的元素都会有自己的弹出框,其输入字段预先填充了名称。不幸的是,情况并非如此,因为在渲染后每个输入字段都设置为数组中最后一个元素的名称。我错过了什么?
Board.js
import React from 'react'
import { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { getActiveBoard } from '../../state/action-creators/activeBoardActions';
import RenamePopover from '../popovers/RenamePopover';
const Board = () => {
const dispatch = useDispatch();
const [anchorEl, setAnchorEl] = React.useState(null);
const boards = useSelector((state) => state.board.items);
const open = Boolean(anchorEl);
useEffect(() => {
dispatch(getActiveBoard());
}, [boards])
const handleClick = (id) => {
const anchor = document.getElementById(`board-anchor${id}`);
setAnchorEl(anchor);
};
const handleClose = () => {
setAnchorEl(null);
};
const single_board = boards && boards.map((board) => {
return (
<li key={board.id} className={`row hovered-nav-item board-item ${active_board == board.id ? "item-selected" : ""}`}>
<span className="d-flex justify-content-between">
<div onClick={() => onBoardClick(board.id)} className="fs-5 text-white board-name" id={`board-anchor${board.id}`}>
{board.name}
</div>
<svg onClick={() => handleClick(board.id)} xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
className="bi bi-pen-fill rename-add-icon rename-add-icon-sidebar"
viewBox="0 0 16 16">
<path
d="m13.498.795.149-.149a1.207 1.207 0 1 1 1.707 1.708l-.149.148a1.5 1.5 0 0 1-.059 2.059L4.854 14.854a.5.5 0 0 1-.233.131l-4 1a.5.5 0 0 1-.606-.606l1-4a.5.5 0 0 1 .131-.232l9.642-9.642a.5.5 0 0 0-.642.056L6.854 4.854a.5.5 0 1 1-.708-.708L9.44.854A1.5 1.5 0 0 1 11.5.796a1.5 1.5 0 0 1 1.998-.001z" />
</svg>
<RenamePopover
open={open}
anchorEl={anchorEl}
onClose={handleClose}
placeholder="Enter new name"
value={board.name}
/>
</span>
</li>
)
})
return(
<div className="container" id="sidebar-boards">
{single_board}
</div>
)
}
export default Board
重命名Popover.js
import { Popover } from '@material-ui/core'
import React from 'react'
const RenamePopover = (props) => {
const [value, setValue] = React.useState(props.value);
const handleChange = (e) => {
setValue(e.target.value);
}
return (
<Popover
open={props.open}
anchorEl={props.anchorEl}
onClose={props.onClose}
anchorOrigin={{
vertical: 'center',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'center',
horizontal: 'left',
}}
>
<input autoFocus={true} className="card bg-dark text-light add-input" type="text"
placeholder={props.placeholder}
value={value}
onChange={handleChange}
/>
</Popover>
)
}
export default RenamePopove
r
解决方案
问题
这个问题是您正在为弹出框使用单个open
“状态”。您将 设置为anchorEl
正在与之交互的元素,然后打开所有弹出框。
解决方案 1
添加open
状态以跟踪您要打开的特定板元素。
const Board = () => {
...
const [anchorEl, setAnchorEl] = React.useState(null);
const [open, setOpen] = React.useState(null); // <-- add state to hold id
...
const handleClick = (id) => {
const anchor = document.getElementById(`board-anchor${id}`);
setAnchorEl(anchor);
setOpen(id);
};
const handleClose = () => {
setAnchorEl(null);
setOpen(null);
};
const single_board =
boards &&
boards.map((board) => {
return (
<li
key={board.id}
className={`row hovered-nav-item board-item ${active_board == board.id ? "item-selected" : ""}`}
>
<span className="d-flex justify-content-between">
<div
onClick={() => handleClick(board.id)}
className="fs-5 text-white board-name"
id={`board-anchor${board.id}`}
>
{board.name}
</div>
...
<RenamePopover
open={open === board.id} // <-- match board id
anchorEl={anchorEl}
onClose={handleClose}
placeholder="Enter new name"
value={board.name}
/>
</span>
</li>
);
});
...
解决方案 2
使用open
状态来保存board
您想要打开/渲染的全部数据并渲染单个弹出框。您需要向useEffect
popover 组件添加一个钩子来处理重置本地状态。
const RenamePopover = (props) => {
const [value, setValue] = React.useState(props.value);
React.useEffect(() => {
setValue(props.value);
}, [props.value]);
const handleChange = (e) => {
setValue(e.target.value);
};
return (
<Popover
open={props.open}
anchorEl={props.anchorEl}
onClose={props.onClose}
anchorOrigin={{
vertical: "center",
horizontal: "right"
}}
transformOrigin={{
vertical: "center",
horizontal: "left"
}}
>
<input
autoFocus={true}
className="card bg-dark text-light add-input"
type="text"
placeholder={props.placeholder}
value={value}
onChange={handleChange}
/>
</Popover>
);
};
const Board = () => {
...
const [anchorEl, setAnchorEl] = React.useState(null);
const [open, setOpen] = React.useState(null);
...
const handleClick = (board) => {
const anchor = document.getElementById(`board-anchor${board.id}`);
setAnchorEl(anchor);
setOpen(board);
};
const handleClose = () => {
setAnchorEl(null);
setOpen(null);
};
const single_board =
boards &&
boards.map((board) => {
return (
<li
key={board.id}
className={`row hovered-nav-item board-item ${active_board == board.id ? "item-selected" : ""}`}
>
<span className="d-flex justify-content-between">
<div
onClick={() => handleClick(board)}
className="fs-5 text-white board-name"
id={`board-anchor${board.id}`}
>
{board.name}
</div>
...
</span>
</li>
);
});
return (
<div className="container" id="sidebar-boards">
{single_board}
<RenamePopover // <-- render 1 popover
open={open}
anchorEl={anchorEl}
onClose={handleClose}
placeholder="Enter new name"
value={open?.name}
/>
</div>
);
};
推荐阅读
- r - 给定地理空间数据的配对位置
- istio - 使用 Istio 的 Envoy Preserve Case Formatter
- python-3.x - 无法使用自定义数据集:AttributeError:“列表”对象没有属性“键”
- jfrog - 在 jfrog 上拉取 docker image pull 时出错(本地)
- java - Apache Cassandra 与 python、java 和 spring boot 的兼容性问题
- nginx - 允许未经身份验证的访问
- javascript - 编辑行的值并在搜索后选择存储后如何设置引导表扩展的样式?
- javascript - React 和 SCSS webapp 仅在 Firefox 中正确格式化,但在 Chrome 或 Safari 中不正确
- python - 如何在列表理解中获取元组列表
- python - 从数据框中删除列时出现问题(最新的 dask 2021.04.1)