gpt4 book ai didi

javascript - 为什么setState在循环中插入重复值

转载 作者:行者123 更新时间:2023-11-30 09:12:12 25 4
gpt4 key购买 nike

我有两个逻辑上依赖的 HTML 选择组件。

第一个代表Districts列表,第二个代表相应的Subdistricts。

选择一个区后,应更改“子区”选项数组以代表所选区的子区。

以下是它们在组件渲染方法中的表示方式:

  <div style={{display: "inline-block", marginRight: "20px"}}>
<h style={{fontSize: "20px"}}>District</h>
<br/>
<select id="districts-select-list" onChange={this.updateDistrictData}>
{this.state.districtsSelectOptionsArrayState}
</select>
</div>

<div style={{display: "inline-block"}}>
<h style={{fontSize: "20px"}}>Subdistrict</h>
<br/>
<select id="subdistricts-select-list">
{this.state.subdistrictsSelectOptionsArrayState}
</select>
{this.state.subdistrictsSelectOptionsArrayState}
</div>

如您所见,选项取决于状态。

以下是更新数据的方法:

updateDistrictData(e) {
this.setState({subdistrictsSelectOptionsArrayState : []});

var categoryList = document.getElementById("districts-select-list");
var selectedDistrictId = categoryList.options[categoryList.selectedIndex].value;

if(selectedDistrictId == undefined) {
return;
}

var currentSubdistrictList = this.subdistrictDataArray[selectedDistrictId];

if(currentSubdistrictList != undefined) {
var currentSubdistrictListLength = currentSubdistrictList.length;

if(
currentSubdistrictListLength == undefined ||
currentSubdistrictListLength == 0
) {
return;
}

for(var index = 0; index < currentSubdistrictListLength; index++) {
var currentDistrictObject = currentSubdistrictList[index];

if(currentDistrictObject != undefined) {
var currentSubdistrictId = currentDistrictObject["id"];
var currentSubdistrictName = currentDistrictObject["name"];

console.log("SUBDISTRICT NAME IS : " + currentSubdistrictName);

var currentSubdistrictOption = (
<option value={currentSubdistrictId}>
{currentSubdistrictName}
</option>
);

this.setState(prevState => ({
subdistrictsSelectOptionsArrayState:[
...prevState.subdistrictsSelectOptionsArrayState,
(
<option value={currentSubdistrictId}>
{currentSubdistrictName}
</option>
)
]
}));

}

}

}

}

从服务器检索分区后,我调用 updateDistrictData 方法,并在 District select 组件的 onChange 方法中调用 updateDistrictData 方法。

第一次加载页面时,区和相应的分区会正确更改。

但是,当我随后使用“地区选择组件”本身更改地区时,子地区选择组件会填充重复的子地区选项,重复次数与当前地区的子地区数量相同。

我做错了什么?

最佳答案

该问题是由于在闭包(setState 回调)中使用 var(currentSubdistrictId 和 currentSubdistrictName)引起的。

=> 由于 var 声明,currentSubdistrictId 和 currentSubdistrictName 所采用的最后一个值用于所有选项。

当与 var(某种全局范围)一起使用时,js 中的闭包确实很棘手。

由于您使用的是 es6,因此应该正确使用 let (在 for 循环中的索引等 block 内修改)和 const (在声明时仅设置一次 block )变量声明,并且永远不要使用 var (某种全局范围)。

class App extends React.Component {
districtDataArray = [
{ name: 'A', id: 0 },
{ name: 'B', id: 1 },
{ name: 'C', id: 2 },
]
subdistrictDataArray = [
[
{ name: 'AA', id: 0 },
{ name: 'AB', id: 1 },
{ name: 'AC', id: 2 },
],
[
{ name: 'BA', id: 0 },
{ name: 'BB', id: 1 },
{ name: 'BC', id: 2 },
],
[
{ name: 'CA', id: 0 },
{ name: 'CB', id: 1 },
{ name: 'CC', id: 2 },
],
]

state = {
districtsSelectOptionsArrayState: this.districtDataArray.map(d => (
<option value={d.id}>
{d.name}
</option>
)),
subdistrictsSelectOptionsArrayState: [],
}

constructor(props) {
super(props);
this.updateDistrictData = this.updateDistrictData.bind(this);
}

updateDistrictData(e) {
this.setState({subdistrictsSelectOptionsArrayState : []});

const categoryList = document.getElementById("districts-select-list");
const selectedDistrictId = categoryList.options[categoryList.selectedIndex].value;

if(!selectedDistrictId) {
return;
}

const currentSubdistrictList = this.subdistrictDataArray[selectedDistrictId];

if(currentSubdistrictList) {
const currentSubdistrictListLength = currentSubdistrictList.length;

if(!currentSubdistrictListLength) {
return;
}

for(let index = 0; index < currentSubdistrictListLength; index++) {
// use const for block level constant variables
const currentDistrictObject = currentSubdistrictList[index];

if(currentDistrictObject) {
// use const for block level constant variables
const currentSubdistrictId = currentDistrictObject["id"];
const currentSubdistrictName = currentDistrictObject["name"];

console.log("SUBDISTRICT NAME IS : " + currentSubdistrictName);

const currentSubdistrictOption = (
<option value={currentSubdistrictId}>
{currentSubdistrictName}
</option>
);

this.setState(prevState => ({
subdistrictsSelectOptionsArrayState:[
...prevState.subdistrictsSelectOptionsArrayState,
(
<option value={currentSubdistrictId}>
{currentSubdistrictName}
</option>
)
]
}));

}

}

}

}
render() {

return (
<div>
<div style={{display: "inline-block", marginRight: "20px"}}>
<h style={{fontSize: "20px"}}>District</h>
<br/>
<select id="districts-select-list" onChange={this.updateDistrictData}>
{this.state.districtsSelectOptionsArrayState}
</select>
</div>

<div style={{display: "inline-block"}}>
<h style={{fontSize: "20px"}}>Subdistrict</h>
<br/>
<select id="subdistricts-select-list">
{this.state.subdistrictsSelectOptionsArrayState}
</select>
{this.state.subdistrictsSelectOptionsArrayState}
</div>
</div>
);
}
}

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

此外,在 updateDistrictData 中更新状态的方式非常低效(n + 1 setStates,n 在循环中,n 是分区的数量)。

您应该计算变量的最终状态,并在计算完成后立即将其全部设置。

虽然我的实现解释了代码的问题,但没有对其进行太多更改,Jared 下面的答案是一个很好的例子,说明如何可以更干净地完成它。

关于javascript - 为什么setState在循环中插入重复值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57745285/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com