在使用钩子的函数组件react中,有没有不同的方法可以用e.target.value设置State



我对react很陌生,一直在通过教程学习。现在,由于react一直在使用钩子推广功能组件,我一直在尝试将教程中基于类的方法转换为功能组件的新react语法。以下代码中的所有内容都很好,除了我试图将AddNinja组件的状态设置为输入值时。

以下是三个组件——主组件(工作正常(、显示组件(工作良好(和问题组件。还有教程中使用类教授的问题组件的原始版本,效果很好。只有我版本的问题组件(AddNinja(不起作用。

这是主组件(运行良好(:


import React, { useState } from 'react';
import Ninjas from './Ninjas';
import AddNinja from './AddNinja';
function App() {
const [ninjas, setNinja] = useState([
{ name: 'Ryu', age: 34, belt: 'blackbelt', id: 1 },
{ name: 'Yuu', age: 32, belt: 'yellowbelt', id: 2 },
{ name: 'Lee', age: 31, belt: 'redbelt', id: 3 },
{ name: 'Shawn', age: 34, belt: 'blackbelt', id: 4 },
{ name: 'Mario', age: 34, belt: 'blackbelt', id: 5 },
{ name: 'Rhea', age: 34, belt: 'blackbelt', id: 6 },

])
const addNinja = (ninja) => {
ninja.id = Math.random() * 10;
let addedNinjas = setNinja([...ninjas, ninja]);
return addedNinjas;
}
const deleteNinja = id => {
let remainingNinjas = ninjas.filter(ninja => ninja.id !== id);
console.log(remainingNinjas);
let newArray = setNinja([...remainingNinjas]);
return newArray
}
return (
<div className="App">
<h1>My first React App</h1>
<p>Welcome</p>
<Ninjas deleteNinja={deleteNinja} ninjas={ninjas} />
<AddNinja addNinja={addNinja} />
</div>
)

}
export default App;

这是显示组件(以防您需要运行代码((工作正常(

import React from 'react';
const Ninjas = ({ninjas, deleteNinja}) => {
const ninjaList = ninjas.map(ninja => {
return ninja.age > 31 ? (
<div className='ninja' key={ninja.id}>
<div>Name: {ninja.name}</div>
<div>Age: {ninja.age}</div>
<div>Belt: {ninja.belt}</div>
<button onClick={() => {deleteNinja(ninja.id)} }>Delete</button>
</div>
) : null
});
return (
<div className='ninja-list'>
{ninjaList}
</div>
)

}
export default Ninjas;

这就是问题的组成部分。。除了handleSubmit函数外,在使用钩子将基于类转换为函数时,它中的一切都很好。在输入时,它会对值进行精细记录,但在提交时会将除最后一个值(皮带(外的所有值返回为未定义值。就好像它忘记了其他的价值观。

import React, { useState } from 'react';
const AddNinja = ({ addNinja }) => {
const [newNinjas, setNewNinja] = useState(
{
name: null,
age: null,
belt: null
}
);
const handleChange = e => {
setNewNinja({
[e.target.id]: e.target.value
});
}
const handleSubmit = (e) => {
e.preventDefault();
console.log('submit', newNinjas.age, newNinjas.belt)
addNinja(newNinjas);
// document.querySelector('form').reset();
}
return (
<div>
<form onSubmit={handleSubmit}>
<label htmlFor="name">Name:</label>
<input type="text" id="name" onChange={handleChange} />
<label htmlFor="age">Age:</label>
<input type="text" id="age" onChange={handleChange} />
<label htmlFor="belt">Belt:</label>
<input type="text" id="belt" onChange={handleChange} />
<button>Submit</button>
</form>
</div>
)
}
export default AddNinja;

我做错了什么?我应该在这里使用useEffects吗?如果是,你能告诉我如何在代码中做到这一点吗?

此外,如果你想看看导师教授的原始基于类的组件,它工作得很好,顺便说一句,它是:(工作得好(

import React, { Component } from 'react';
class AddNinja extends Component{
state = {
name: null,
age: null,
belt: null
}
handleChange = e => {
this.setState({
[e.target.id]: e.target.value
});
// console.log(this.state)
}
handleSubmit = e => {
e.preventDefault();
// console.log(this.state);
this.props.addNinja(this.state);
document.querySelector('form').reset();
}
render(){
return (
<div>
<form onSubmit={this.handleSubmit}>
<label htmlFor="name">Name:</label>
<input type="text" id="name" onChange={this.handleChange}/>
<label htmlFor="name">Age:</label>
<input type="text" id="age" onChange={this.handleChange}/>
<label htmlFor="name">Belt:</label>
<input type="text" id="belt" onChange={this.handleChange}/>
<button>Submit</button>
</form>
</div>
)
}
}
export default AddNinja;

非常感谢您的阅读!

useState获得的setter和类组件setState方法之间的最大区别在于,useState中的setter不像setState那样合并。所以这个:

setNewNinja({
[e.target.id]: e.target.value
});

完全覆盖CCD_ 5中的现有值。

相反,将你的新忍者合并到现有对象中:

setNewNinja({
...newNinjas, 
[e.target.id]: e.target.value
});

如果您不处理newNinjas中的陈旧状态,那么该版本就可以了。大多数情况下都是这样,但有时您不想担心newNinjas是否过时(有关更多信息,请参阅Dan Abramov的这篇文章(。在这些情况下,使用回调版本:

setNewNinja(current => ({
...current, 
[e.target.id]: e.target.value
}));

useState:的文档中对此有一条注释

注意

与类组件中的setState方法不同,useState不会自动合并更新对象。您可以通过将函数更新器形式与对象扩展语法相结合来复制这种行为:

setState(prevState => {
// Object.assign would also work
return {...prevState, ...updatedValues};
});

另一个选项是useReducer,它更适合管理包含多个子值的状态对象。

相关内容

最新更新