功能组件中的e.target.value是否有不同的setState方法使用钩子进行反应?

时间:2020-02-28 17:30:51

标签: javascript reactjs

我是一个非常新的反应者,一直在通过教程学习它。现在,由于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;

非常感谢您的阅读!

1 个答案:

答案 0 :(得分:3)

useState获得的setter和类组件setState方法之间的最大区别是,useState的setter不会像{ {1}}可以。所以这个:

setState

完全覆盖setNewNinja({ [e.target.id]: e.target.value }); 中的现有值。

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

newNinjas

如果您不处理setNewNinja({ ...newNinjas, [e.target.id]: e.target.value }); 中的陈旧状态,则该版本很好。大多数情况下都是这样,但是有时您不必担心newNinjas是否过时(有关更多信息,请参见Dan Abramov的this article)。在这种情况下,请使用回调版本:

newNinjas

the documentation for useState中有关于此的注释:

注意

与类组件中的setNewNinja(current => ({ ...current, [e.target.id]: e.target.value })); 方法不同,setState不会自动合并更新对象。您可以通过将函数更新程序形式与对象传播语法结合在一起来复制此行为:

useState

另一个选项是setState(prevState => { // Object.assign would also work return {...prevState, ...updatedValues}; }); ,它更适合于管理包含多个子值的状态对象。