React setState使用点或括号表示法设置动态键名失败如何解决?
React动态设置state对象键名问题
问题描述
需要为动态数据集设置state,数据加载完成后在componentDidUpdate生命周期函数中遍历数据集,尝试根据每个元素的Id为其在state中设置对应状态。选择使用id而非索引,是因为数据渲染后索引无法被访问,无法用于定位元素。
尝试设置state时IDE抛出语法错误,提示点表示法或括号表示法不符合预期,原始代码如下:
componentDidUpdate(prevProps, prevState){ if(this.props.report !== prevProps.report && this.props.report !== undefined){ //set checkbox state dynamically for each row this.props.report.systemSourceList.forEach((item) => this.setState((prevState) => ({selectedSourceRowIds : [...prevState.selectedSourceRowIds, {item['sourceId']: true}]})) } }
先后尝试了item.sourceId和item['sourceId']两种写法均无法正常运行。将item.sourceId赋值给变量id后,控制台可以正常打印id的取值,但将该变量作为对象键名传入时,最终生成的对象键为固定字符串"id",而非id变量对应的实际值,对应代码如下:
this.props.report.systemSourceList.forEach((item) => { let id = item.sourceId; console.log(id); this.setState((prevState) => ({selectedSourceRowIds : [...prevState.selectedSourceRowIds, {id: true}]})) }); }
遍历的对象结构如下:
{ systemId: 13, facilityId: 4747, sourceId: "WS010", }
错误原因
该问题由JavaScript对象字面量的语法规则导致:
- ES6之前的标准中,对象字面量的键只能是固定字符串,书写
{id: true}时,JS会直接将id识别为字符串类型的键名,不会读取对应变量的实际值 - 直接书写
{item['sourceId']: true}不符合原生JS语法规范,因此IDE会抛出语法错误
解决方案
使用ES6新增的计算属性名语法即可解决该问题,只需给动态键名外层包裹方括号,JS会先计算变量的实际值,再作为对象的键名使用,最终可运行的代码如下:
this.props.report.systemSourceList.forEach((item) => { let id = item.sourceId; console.log(id); this.setState((prevState) => ({selectedSourceRowIds : [...prevState.selectedSourceRowIds, {[id]: true}]})) });
优化方案
上述实现遍历数组时多次调用setState,每次调用都会触发组件更新逻辑,存在不必要的性能开销。可先批量处理好要新增的项,再一次性更新state,优化后代码如下:
componentDidUpdate(prevProps, prevState){ // 可选链判断避免属性不存在时报错 if(this.props.report !== prevProps.report && this.props.report?.systemSourceList){ // 批量生成所有要新增的对象项 const newSourceItems = this.props.report.systemSourceList.map(item => ({ [item.sourceId]: true })) // 一次性更新state,仅触发一次重渲染 this.setState(prevState => ({ selectedSourceRowIds: [...prevState.selectedSourceRowIds, ...newSourceItems] })) } }
内容的提问来源于stack exchange,提问作者reactFullStackDeveloper
相关产品推荐
相关产品推荐

