React新手删除按钮触发错误函数及setState写法规范咨询
React新增/删除列表功能故障及规范问题解答
一、原始故障代码的问题定位
你遇到的删除按钮触发新增逻辑的问题,一共存在3处错误:
- 构造函数内方法绑定错误:
this.elimFunction = this.clickFunction.bind(this)这行代码把删除方法错误绑定成了新增方法,自然点击删除会触发新增逻辑,需要改成this.elimFunction = this.elimFunction.bind(this) - 删除索引传参错误:调用删除方法时你传的是
{i}(包裹了一层对象),不是数字类型的索引,需要改成this.elimFunction(i) - splice用法错误:
Array.splice()的返回值是被删除的元素组成的数组,不是修改后的原数组,直接把返回值赋值给列表会导致列表只剩下被删除的条目,需要先拷贝原数组再操作。
二、可运行版本的规范问题说明
你担心的“setState写在render里”属于理解误区:你并没有在render的同步执行流程中调用setState,只是把setState写在了按钮的点击事件回调里,回调只会在你主动点击按钮时触发,不会在渲染阶段执行,因此不会触发无限重渲染的问题。
但这个写法仍然不符合最佳实践,存在两个问题:
- 视图和业务逻辑耦合:所有新增、删除逻辑都堆在JSX的回调内,代码量变大后可读性、可维护性会非常差,也不利于逻辑复用
- 直接修改原始state:删除逻辑中
this.state.list.splice(i, 1)直接修改了state里的原数组,违反了React状态不可变的设计原则,可能引发潜在的渲染异常。
三、符合最佳实践的参考代码
<html> <head> <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Faker/3.1.0/faker.min.js"></script> </head> <body> <div id='root'></div> <script type='text/babel'> const { render } = ReactDOM; const { Component } = React; class App extends Component{ constructor(){ super(); this.state = { companyList: ['Some Company'] } // 正确绑定两个方法的this指向 this.addCompany = this.addCompany.bind(this) this.deleteCompany = this.deleteCompany.bind(this) } // 新增逻辑抽离为独立方法 addCompany() { const newCompany = faker.company.companyName() this.setState({ companyList: [...this.state.companyList, newCompany] }) } // 删除逻辑抽离为独立方法,遵循不可变原则 deleteCompany(index) { // 过滤得到新数组,不修改原state const newList = this.state.companyList.filter((_, i) => i !== index) this.setState({ companyList: newList }) } render(){ return ( <div> <button onClick={this.addCompany}> 点击新增公司 </button> <ul> { this.state.companyList.map((e,i)=> <li key={i}> {e} <button onClick={() => this.deleteCompany(i)}>删除</button> </li> ) } </ul> </div> ) } } render(<App />, document.querySelector('#root')); </script> </body> </html>
内容的提问来源于stack exchange,提问作者Ken
相关产品推荐
相关产品推荐

