TypeError:无法设置未定义App.inputChangeHandler的属性'eName'

时间:2019-10-17 16:25:42

标签: reactjs react-native

一旦用户更新输入的收件箱,显示的eName就会更改。它不更新阵列。是什么原因造成的?

错误消息:

  

TypeError:无法设置未定义App.inputChangeHandler的属性'eName'

代码:

class App extends Component {
  state= {
    product:[
      {eName:"Anu", eNo:"1200", eSalary:"1000"},
      {eName:"Jack", eNo: "1201", eSalary:"1200"},
      {eName:"Ben", eNo: "1202", eSalary:"1300"}
    ],
    showFlag:true,
  }

  inputChangeHandler(event,index){
    const mProducts = this.state.product;
    mProducts[index].eName = event.target.value;
    console.log(event.target.value);
    this.setState({
       product:mProducts
    })
  }

  deleteHandler(index){
    console.log("delete clicked" + index);
    const mProducts = this.state.product;
    mProducts.splice(index,1);
    this.setState({
      product:mProducts
    })
  }

  showHideHandler=()=>{
    this.setState({
      showFlag:!this.state.showFlag
    })
    console.log(this.state.showFlag);
  }

  render(){
    let dp = null;
    if (this.state.showFlag === true){
      dp =(
        <div className ="App">
          {this.state.product.map((product,index) => {
            return (
            <Product
              eName={product.eName}
              eNo={product.eNo}
              eSalary={product.eSalary}
              key ={index}
              click ={this.deleteHandler.bind(this.index)}
              inputChange={this.inputChangeHandler.bind(this)}
            />)
          })}
        </div>
      )
    }
    return(
      <div className ="App">
        {dp}
        <hr/>
        <button onClick={()=>this.showHideHandler()}>show hide</button>
        <h2>{this.state.eName} </h2>
      </div>
    );
  }
}

export default App;

一旦用户更新输入的收件箱,显示的eName就会更改。它不更新阵列。

3 个答案:

答案 0 :(得分:0)

问题是因为inputChangeHandler函数未收到正确的索引。请进行以下更改:

inputChangeHandler定义为箭头函数:

inputChangeHandler = (event,index) => {
    const mProducts = this.state.product;
    mProducts[index].eName = event.target.value;
    console.log(event.target.value);
    this.setState({
       product:mProducts
    })
  }

render函数内部,在调用inputChangeHandler时,同时传递事件和索引

render(){
        let dp = null;
        if (this.state.showFlag === true){
          dp =(
            <div className ="App">
              {this.state.product.map((product,index) => {
                return (
                <Product
                  eName={product.eName}
                  eNo={product.eNo}
                  eSalary={product.eSalary}
                  key ={index}
                  click ={this.deleteHandler.bind(this.index)}
                  inputChange={(e) => this.inputChangeHandler(e, index)}
                />)
              })}
            </div>
          )
        }
        return(
          <div className ="App">
            {dp}
            <hr/>
            <button onClick={()=>this.showHideHandler()}>show hide</button>
            <h2>{this.state.eName} </h2>
          </div>
        );
}

答案 1 :(得分:0)

您正在更改状态,并在所有处理程序中使用已更改状态执行setState。因为React看不到状态变化,所以它不会重新呈现(尝试将console.log放入render中,您会看到它不会显示在控制台中)。

以下是您在不更改状态的情况下将其设置为状态的方法:

inputChangeHandler(event, index) {
  this.setState({
    product: this.state.product.map((product, i) =>
      i === index
        ? { ...product, eName: event.target.value }
        : product
    ),
  });
}

我建议最好为变量命名,如果您有产品列表,则最好将其命名为products(复数)而不是product(单数)。

如果您让React渲染元素列表并且可以删除或排序元素,那么您不应该将index用作键,产品不具有可以使用的唯一ID,否则请问为什么?

以下是如何将事件处理程序发送到产品的示例:

class App extends React.Component {
  state = {
    products: [
      { id: 1, eName: 'Anu', eNo: '1200', eSalary: '1000' },
      {
        id: 2,
        eName: 'Jack',
        eNo: '1201',
        eSalary: '1200',
      },
      { id: 3, eName: 'Ben', eNo: '1202', eSalary: '1300' },
    ],
    showFlag: true,
  };
  //arrow function will auto bind
  inputChangeHandler = (eName, id) => {
    this.setState({
      products: this.state.products.map(p =>
        p.id === id ? { ...p, eName } : p
      ),
    });
  };
  //arrow function will auto bind
  deleteHandler = id => {
    this.setState({
      products: this.state.products.filter(
        p => p.id !== id
      ),
    });
  };

  showHideHandler = () => {
    this.setState({
      showFlag: !this.state.showFlag,
    });
  };

  render() {
    let dp = null;
    if (this.state.showFlag === true) {
      dp = (
        <div className="App">
          {this.state.products.map((product, index) => {
            return (
              <Product
                key={product.id}
                {...product}
                remove={this.deleteHandler}
                inputChange={this.inputChangeHandler}
              />
            );
          })}
        </div>
      );
    }
    return (
      <div className="App">
        {dp}
        <hr />
        <button onClick={() => this.showHideHandler()}>
          show hide
        </button>
        <h2>{this.state.eName} </h2>
      </div>
    );
  }
}

//make this a pure component with React.memo
const Product = React.memo(function Product({
  remove,
  id,
  eName,
  inputChange,
}) {
  console.log('rendering:', id);
  return (
    <div>
      <button onClick={() => remove(id)}>delete</button>
      <input
        type="text"
        value={eName}
        onChange={e => inputChange(e.target.value, id)}
      ></input>
    </div>
  );
});



//render app
ReactDOM.render(
  <App />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

答案 2 :(得分:0)

您还应该将index传递给Product组件,

{this.state.product.map((product,index) => {
  return (
    <Product
      eName={product.eName}
      eNo={product.eNo}
      eSalary={product.eSalary}
      key = {index}
      ind = {index}   //pass index here
      click ={this.deleteHandler.bind(this.index)}
      inputChange={this.inputChangeHandler.bind(this)}
    />
  )
})}

您的Product组件应为(根据您的评论)

import React from 'react'
import './employee.css'
function Employee(props) { 
    return (
        <div className ="prod"> 
            <h1> Name:{props.eName}</h1> 
            <h2> Emp-No:{props.eNo}</h2> 
            <h3> Salary:{props.eSalary}</h3> 
            <button onClick ={props.click}> delete</button> 
            <input onChange={(e) => props.inputChange(e,props.ind)} value={props.eName} type="text"/>  //pass `event` & `index` to `inputChange` function here
        </div>
    ) 
}
export default Employee;