下午好, 我有一个React组件,它响应API调用动态呈现。我已将其中一个元素的值设置为组件中的状态。在onClick函数(minusOne)期间,该值应该更改。 该值最初基于状态成功呈现,该函数确实改变了状态,但是尽管状态改变,但渲染的元素保持不变。有没有人知道为什么会这样? 如果您有任何疑问,请随时联系!
export class Cart extends React.Component {
constructor(props) {
super(props);
this.state={
quantities: []
};
this.minusOne = this.minusOne.bind(this);
}
minusOne(i) {
var self = this;
return function() {
let quantities = self.state.quantities;
if (quantities[i] > 1) {
quantities[i] --;
}
self.setState({
quantities
})
}
}
componentDidMount() {
let cart = this.props.cartTotals;
this.setState({
cart
});
if(cart.lines) {
let cartTotal = [];
let quantities = [];
for (var i = 0; i < cart.lines.length; i++) {
if(cart.lines[i]) {
quantities.push(cart.lines[i].quantity);
}
}
//Initial setting of state
this.setState({
quantities
})
Promise.all(
cart.lines.map(
(cart, i) => axios.get('http://removed.net/article/' + cart.sku)
)
).then(res => {
const allCartItems = res.map((res, i) => {
const data = res.data;
return(
<div key={i} className="cart-item-container">
<img className ="cart-item-picture" src={data.image} name={data.name} />
<div className="cart-item-description">
<p>{data.name}</p>
<p>{data.price.amount} {data.price.currency}</p>
</div>
<div className="cart-item-quantity">
<button onClick={this.minusOne(i)} name="minus">-</button>
//This is the troublesome element
<p className="cart-current-quantity">{this.state.quantities[i]}</p>
<button name="plus">+</button>
</div>
</div>
)
})
this.setState({
allCartItems
})
})
}
}
render() {
return (
{this.state.allCartItems}
);
}
}
感谢阅读!任何建议都会有所帮助。
答案 0 :(得分:0)
有两个问题:
onClick
所在的位置)。 ConponentDidMount
只被调用一次,并且应该执行初始化但不能渲染。minusOne
中出现问题:quantities
指向this.state.quantities
。因此,您正在更改旧状态,React查看旧状态和新状态,看到没有更改,并且dodes没有渲染,尽管值已更改。如果要将this.state.quantities复制到新数组,例如:
newQ = this.state.quantities.slice(0, -1);
然后修改newQ,然后执行
this.setState({ quantities: newQ });
它应该有用。
答案 1 :(得分:0)
---编辑--- 我删除了之前写的所有内容,以使其更简洁。
您的问题是您要将要渲染的内容分配给componentDidMount
中的变量。此函数只调用一次,因此您只需将变量allCartItems赋值一次。 setState
函数没有任何效果,因为它不会触发componentDidMount
,因此您的变量allCartItems不会被重新分配。
你能做什么?那么你可以做很多事情来增强你的代码。首先,我会告诉您如何解决问题,然后再给您一些改进
要解决在调用setState
时组件未更新的问题,应将jsx移动到渲染方法。在componentDidMount
中,您只需获取渲染组件所需的所有数据,一旦拥有它,您就可以设置一个标志,例如ready to true。您可以在下面看到代码看起来如何的示例。
import React from 'react';
class Cart extends React.Component {
constructor(props) {
super(props);
this.state = {
carts: null,
ready: false,
};
}
componentDidMount() {
fetch('www.google.com').then((carts) => {
this.setState({
carts,
ready: true,
});
});
}
render() {
const myCarts = <h2> Count {this.state.carts} </h2>;
return (
{
this.state.ready
? myCarts
: <h2> Loading... </h2>
}
);
}
}
我为您制作了一个带有简单计数器的演示,其中包含对您的案例的一些解释以及如何使其工作。你可以查看codesandbox。在NotWorkingCounter中,您可以看到与未更新的变量组件中的问题相同的问题。在WorkingCount中,您可以看到一个示例,其中我实现了上面写的内容,等待数据到达,然后再渲染它。
有关代码的更多建议:
下面的这两个语法是相同的。一个更简洁。
class Cart extends React.Component {
constructor(props) {
super(props);
this.state = {
carts: null,
ready: false,
};
}
}
class Cart extends React.Component {
state = {
carts: null,
ready: false,
}
}
如果你想绑定你的上下文,我建议使用arrow函数。下面你可以看到你的例子简化了,以及如何用较少的语法实现同样的事情的例子。
export class Cart extends React.Component {
constructor(props) {
super(props);
this.minusOne = this.minusOne.bind(this);
}
minusOne(i) {
///
}
}
export class Cart extends React.Component {
constructor(props) {
super(props);
}
minusOne = (i) => {
/// minus one function
}
}
如果使用箭头功能并且要小得多,那么你的minusOne也可以重写,
minusOne = (i) => (i) => {
let quant = self.state.quantities[i];
if(quant > 1) {
this.setState({
quantities: quant-1,
})
}
}
在componentDidMount
中,您拨打this.setState
两次。每次调用此函数时,您的组件都会被重新渲染。所以在你的组件中发生的事情是当你的组件第一次被渲染时,一旦它被挂起componentDidMount
被调用,你再次调用this.setState
两次。这意味着在用户看到您的组件之前,您的组件将在最佳情况下呈现三次。如果你得到多个承诺,这意味着你会更多地回报你的状态。这可以为您的组件创造大量负载以应对。如果您将每个组件重新渲染三次或更多次,则一旦应用程序增长,您最终会遇到一些性能问题。尽量不要多次调用componentDidUpdate中的setState
。
在您的情况下,您第一次拨打setState
是完全没必要的,只是创建负载。您仍然可以访问承诺中的数量。只需在promise.then()结尾处使用两个元素调用setState。
在下面的示例中,您使用索引i作为键。这不是一个好的案例练习,反应也应该在控制台中至少记录一个警告。您需要使用不是索引的唯一标识符。如果您使用索引,您可以获得难以首次亮相的副作用和奇怪的渲染。阅读更多信息here
then(res => {
const allCartItems = res.map((res, i) => {
const data = res.data;
return(
<div key={i} className="cart-item-container">
另一个建议是将所有var
替换为const
或let
,因为var
会将您的变量公开到全局范围。如果您不明白这意味着什么,请阅读this。
最后但并非最不重要的是看看object deconstruction。它可以帮助您清理代码并使其更好地抵御不必要的副作用。
答案 2 :(得分:0)
我认为你不需要在minusOne(i)方法中返回一个函数。只是更新状态就足够了。您应该按特定ID更改数组。
let quantities = self.state.quantities;
let mutatedQuantities = quantities.map((el, index) => {
return (index === i) ? el - 1 : el;
})
this.setState({quantities: [...mutatedQuantities]})