我试图在单击按钮时更新数组的值。但是我不知道如何使用this.setState
来做到这一点。
export default class App extends React.Component {
state = {
counters: [{ name: "item1", value: 0 }, { name: "item2", value: 5 }]
};
render() {
return this.state.counters.map((counter, i) => {
return (
<div>
{counter.name}, {counter.value}
<button onClick={/* increment counter.value here */}>+</button>
</div>
);
});
}
}
单击按钮后如何增加counter.value
?
答案 0 :(得分:2)
考虑将实际计数器重构为自己的组件。由于封装了组件职责,因此简化了状态管理。突然,您不需要更新嵌套的对象数组,而只需更新一个状态属性:
class App extends React.Component {
state = {
counters: [{ name: "item1", value: 0 }, { name: "item2", value: 5 }]
};
render() {
return this.state.counters.map((counter, i) => {
return (
<Counter name={counter.name} count={counter.value} />
);
});
}
}
class Counter extends React.Component {
state = {
count: this.props.count
}
increment = () => {
this.setState({
count: this.state.count+1
})
}
render() {
return (
<div>
{this.props.name}, {this.state.count}
<button onClick={this.increment}>+</button>
</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"></div>
答案 1 :(得分:0)
您可以使用已经必须将计数器映射到新数组的i
,用更新后的计数替换目标项:
() => this.setState(({ counters }) => ({ counters: counters.map((prev, i2) => i === i2 ? { ...counter, count: counter.count + 1 } : prev) }))
答案 2 :(得分:0)
您可以创建这样的点击处理程序
handleClick = (index) => {
this.setState(state => {
const obj = state.counters[index]; // assign the object at the index to a variable
obj.value++; // increment the value in the object
state.counters.splice(index, 1); // remove the object from the array
return { counters: [...state.counters, obj] };
});
}
这样称呼... <button onClick={() => handleClick(i)}>
可以将其缩短。只是想解释一下如何解决
答案 3 :(得分:0)
更新
因为这是现在公认的答案,所以让我在@Auskennfuchs的评论之后再给出另一种最佳方法。在这里,我们使用Object.assign和index
更新当前计数器。通过这种方法,我们避免在map
上使用不必要的counters
。
class App extends React.Component {
state = {
counters: [{ name: "item1", value: 0 }, { name: "item2", value: 5 }]
};
increment = e => {
const {
target: {
dataset: { i }
}
} = e;
const { counters } = this.state;
const newCounters = Object.assign(counters, {
...counters,
[i]: { ...counters[i], value: counters[i].value + 1 }
});
this.setState({ counters: newCounters });
};
render() {
return this.state.counters.map((counter, i) => {
return (
<div>
{counter.name}, {counter.value}
{/* We are using function reference here */}
<button data-i={i} onClick={this.increment}>
+
</button>
</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" />
作为一种替代方法,您可以使用counter
名称,映射到counters
上并增加匹配的数字。
class App extends React.Component {
state = {
counters: [{ name: "item1", value: 0 }, { name: "item2", value: 5 }]
};
increment = name => {
const newCounters = this.state.counters.map(counter => {
// Does not match, so return the counter without changing.
if (counter.name !== name) return counter;
// Else (means match) return a new counter but change only the value
return { ...counter, value: counter.value + 1};
});
this.setState({counters: newCounters});
};
render() {
return this.state.counters.map((counter, i) => {
return (
<div>
{counter.name}, {counter.value}
<button onClick={() => this.increment(counter.name)}>+</button>
</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" />
如果您使用上述处理程序,它将在每个渲染器上重新创建。您可以将其提取到单独的组件中,也可以使用数据集。
class App extends React.Component {
state = {
counters: [{ name: "item1", value: 0 }, { name: "item2", value: 5 }]
};
increment = e => {
const {target} = e;
const newCounters = this.state.counters.map(counter => {
if (counter.name !== target.dataset.name) return counter;
return { ...counter, value: counter.value + 1};
});
this.setState({counters: newCounters});
};
render() {
return this.state.counters.map((counter, i) => {
return (
<div>
{counter.name}, {counter.value}
{ /* We are using function reference here */ }
<button data-name={counter.name} onClick={this.increment}>+</button>
</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" />
答案 4 :(得分:0)
您可以具有一个处理程序,该处理程序将映射counters
并更新所单击按钮的相应计数器项目。在这里,我们从父级作用域中选取i
,并对其进行比较以找到合适的项进行更改。
<button onClick={() => {
this.setState(state => ({
counters: state.counters.map((item, j) => {
// is this the counter that I want to update?
if (j === i) {
return {
...item,
value: item.value + 1
}
}
return item
})
}))
}}>+</button>
答案 5 :(得分:0)
使用Array.splice
可以替换数组内的条目。这将返回一个具有替换值的新数组:
const {counters}= this.state
return counters.map((counter, i) => (
<div key={i}>
{counter.name}, {counter.value}
<button onClick={() => this.setState({
counters: counters.splice(i, 1, {
...counter,
value: counter.value+1,
}
)})}>+</button>
</div>
));
此外,最好的做法是将循环内的每个Fragment赋予自己唯一的key
。您可以摆脱收益,因为map函数内部只有收益。