问题描述
当我在选择框中选择一个 ID 时,我想在名称数组的选定 ID 中放置一个新名称。我使用了 useState 和 useRef,但“拼接”不起作用。我不知道如何将选定的 ID 传递给拼接功能。这对我来说太难了。请帮帮我。
import React,{ useRef,useState } from 'react';
const App = ()=>{
const [names,setNames] = useState([
{id: 1,text: 'aaa'},{id: 2,text: '222'},{id: 3,text: 'bbb'},]);
const [inputText,setInputText] = useState('');
const [nextId,setNextId] = useState(4);
const onChange = e => setInputText(e.target.value);
const inputEl = useRef(null);
const optionId = useRef(null);
const onClick = () => {
const nextNames = names.concat({
id: nextId,text: inputText,});
setNextId(nextId + 1);
setNames(nextNames);
setInputText('');
console.log(inputEl.current);
console.log(optionId.current);
};
const onSelect = id => {
const nextNames = names.splice(id,{id:id,text: inputText});
setNames(nextNames);
setInputText('');
}
const onRemove = id => {
const nextNames = names.filter(name => name.id !== id);
setNames(nextNames);
};
const nameList = names.map(name => (
<li key={name.id} ondoubleclick={()=> onRemove(name.id)}>{name.text}</li>
));
const idOption = names.map((name,index)=>(
<option key={name.id}>{index}</option>
));
return(
<div>
<input value={inputText} onChange={onChange} ref={inputEl}/>
<button onClick={onClick}>추가</button>
<select ref={optionId} onSelect={onSelect}>
<option>ID</option>
{idOption}
<option>last</option>
</select>
<ul>{nameList}</ul>
</div>
);
};
解决方法
Array.prototype.splice 改变它在就地调用的数组,这几乎总是你不 > 当数组是状态的一部分时,想要使用并且在 React 中被认为是反模式。需要对数组进行浅拷贝,才能正确返回新的数组引用,用于 React 的对帐过程。
splice()
方法通过删除或更改数组的内容
替换现有元素和/或添加新元素就地。
由于您要向数组添加新元素或更新现有元素,您首先需要搜索数组以确定需要执行的操作。如果添加新元素,您可以简单地将前一个数组浅复制到新的数组引用中并附加新元素。如果更新现有元素,那么将之前的状态映射到新数组就是您想要的。
const onSelect = id => {
setNames(names => {
// find if match exists
const match = names.find(name => name.id === id);
if (match) {
// match found,map array
return names.map(name => name.id === id
? {
...name,text: inputText,}
: name
);
}
// no match found,concat new data
return names.concat({ id,text: inputText });
});
setInputText('');
}
,
Splice 接受索引,因此检查 reference 将不起作用。
但是您应该使用 slice 代替,因为 splice 会改变您正在处理的数组,并且您不应该直接改变 useState
值。有关详细信息,请参阅切片 reference。
尽管如此,您有更好的选择来完成您想做的事情,例如 map 和 reduce。
这是一个使用 reduce 的例子:
const onSelect = id => {
const nextNames = names.reduce((acc,next) => {
const name = {...next};
// only change the text prop if we find an id match
if (name.id === id) {
name.text = inputText;
}
// copy the name to the new array
return [...acc,name];
},[]);
setNames(nextNames);
setInputText('');
}
,
感谢您的回答。但是,它不能正常工作。下面代码的工作正是我想要的。这些代码是类组件样式,但我需要在 React Hooks 中进行相同的工作。请看下面的代码,如果可能,请更改为带有反应钩子的代码。谢谢。
class App extends React.Component {
constructor() {
super();
this.state = {
components: []
};
}
addNewElement(element,selectedIndex) {
if (selectedIndex == "last") {
this.state.components.push(element);
} else {
this.state.components.splice(selectedIndex,element);
}
this.setState({ components: this.state.components });
}
render() {
let input,option;
// log out state
console.log(this.state.components);
return (
<div>
<h3>{this.state.components.join(",")}</h3>
<input
placeholder="enter element"
ref={node => {
input = node;
}}
/>
<select
className={this.state.components.length ? "" : "hidden"}
ref={node => {
option = node;
}}
>
<option value="" disabled selected>Insert at index...</option>
{this.state.components.map((component,index) =>
<option>{index}</option>
)}
<option>last</option>
</select>
<button
onClick={() => {
this.addNewElement(input.value,option.value);
}}
>
Click
</button>
</div>
);
}
}
ReactDOM.render(<App />,document.getElementById("root"));