反应组件不在状态更改时重新呈现

我有一个 React 类,它将访问一个 API 来获取内容。我已经确认数据正在恢复,但不是重新渲染:

var DealsList = React.createClass({
getInitialState: function() {
return { deals: [] };
},
componentDidMount: function() {
this.loadDealsFromServer();
},
loadDealsFromServer: function() {
var newDeals = [];


chrome.runtime.sendMessage({ action: "findDeals", personId: this.props.person.id }, function(deals) {
newDeals = deals;
});


this.setState({ deals: newDeals });
},
render: function() {
var dealNodes = this.state.deals.map(function(deal, index) {
return (
<Deal deal={deal} key={index} />
);
});
return (
<div className="deals">
<table>
<thead>
<tr>
<td>Name</td>
<td>Amount</td>
<td>Stage</td>
<td>Probability</td>
<td>Status</td>
<td>Exp. Close</td>
</tr>
</thead>
<tbody>
{dealNodes}
</tbody>
</table>
</div>
);
}
});

但是,如果我像下面这样添加一个 debugger,就会填充 newDeals,然后继续,我就会看到数据:

  loadDealsFromServer: function() {
var newDeals = [];


chrome.runtime.sendMessage({ action: "findDeals", personId: this.props.person.id }, function(deals) {
newDeals = deals;
});
debugger
this.setState({ deals: newDeals });
},

这就是所谓的交易清单:

var Gmail = React.createClass({
render: function() {
return (
<div className="main">
<div className="panel">
<DealsList person={this.props.person} />
</div>
</div>
);
}
});
208194 次浏览

这是因为来自 chrome.runtime.sendMessage的响应是异步的; 下面是操作的顺序:

var newDeals = [];


// (1) first chrome.runtime.sendMessage is called, and *registers a callback*
// so that when the data comes back *in the future*
// the function will be called
chrome.runtime.sendMessage({...}, function(deals) {
// (3) sometime in the future, this function runs,
// but it's too late
newDeals = deals;
});


// (2) this is called immediately, `newDeals` is an empty array
this.setState({ deals: newDeals });

当您使用调试器暂停脚本时,您正在给予扩展时间来调用回调; 当您继续时,数据已经到达并且看起来正常工作。

要解决这个问题,你需要在 Chrome 扩展返回数据之后进行 setState调用:

var newDeals = [];


// (1) first chrome.runtime.sendMessage is called, and *registers a callback*
// so that when the data comes back *in the future*
// the function will be called
chrome.runtime.sendMessage({...}, function(deals) {
// (2) sometime in the future, this function runs
newDeals = deals;


// (3) now you can call `setState` with the data
this.setState({ deals: newDeals });
}.bind(this)); // Don't forget to bind(this) (or use an arrow function)

[编辑]

如果这对您不起作用,请查看关于这个问题的其他答案,这些答案解释了组件可能没有更新的其他原因。

我想补充一点,非常简单,但是很容易犯错:

this.state.something = 'changed';

... 然后不明白为什么它不渲染,谷歌和来到这个页面,只是意识到你应该写:

this.setState({something: 'changed'});

只有在使用 setState更新状态时,React 才会触发重新呈现。

另一个非常容易犯的错误,也是问题的根源: 我编写了自己的 shouldComponentUpdate方法,它没有检查我添加的新状态更改。

在我的例子中,我正确地调用了 this.setState({}),但是我的函数没有绑定到这个函数,所以它没有工作。将 .bind(this)添加到函数调用或在构造函数中执行 this.foo = this.foo.bind(this)修复了它。

我在 React-Native 也遇到过同样的问题,API 响应和拒绝没有更新状态

ApiCall () . then (function (resp){ SetState ({ data: resp })//没有更新 }

我用箭头函数改变 function解决了这个问题

apiCall().then((resp) => {
this.setState({data: resp}) // rendering the view as expected
}

对我来说,这是个约束问题。使用箭头函数解决了这个问题,因为箭头函数不创建它自己的 this,它总是绑定到它来自的外部上下文

我的问题是,我使用的是‘ React. PureComponent’,而我应该使用的是‘ React. Component’。

在研究了许多答案之后(其中大部分对于他们的情景是正确的) ,没有一个能解决我的问题,我意识到我的情况有点不同:

在我奇怪的场景中,我的组件是在状态内呈现的,因此无法更新。 下面是一个简单的例子:

constructor() {
this.myMethod = this.myMethod.bind(this);
this.changeTitle = this.changeTitle.bind(this);


this.myMethod();
}


changeTitle() {
this.setState({title: 'I will never get updated!!'});
}


myMethod() {
this.setState({body: <div>{this.state.title}</div>});
}


render() {
return <>
{this.state.body}
<Button onclick={() => this.changeTitle()}>Change Title!</Button>
</>
}

在将代码重构为 没有之后,使主体从状态转换为正常工作状态:)

我的情况有点不同。我想很多像我这样的新手都会被难住——所以在这里分享吧。

我的 state 变量是用 useState 管理的 JSON 对象数组,如下所示:

const [toCompare, setToCompare] = useState([]);

但是,当像下面函数那样更新 toCompare 和 setToCompare 时,re-render 不会触发。把它移动到另一个部分也不起作用。只有当其他事件触发重新呈现时,更新的列表才会显示出来。

const addUniversityToCompare = async(chiptoadd) =>
{
var currentToCompare = toCompare;
currentToCompare.push(chiptoadd);
setToCompare(currentToCompare);
}

这就是我的解决办法。基本上-赋值数组就是复制引用-and response 不会将其视为更改-因为对数组的引用没有被更改-仅仅是其中的内容。所以在下面的代码中-只是使用切片复制数组-没有任何改变-并在调整后返回给它。完全没问题。

const addUniversityToCompare = async (chiptoadd) => {
var currentToCompare = toCompare.slice();
currentToCompare.push(chiptoadd);
setToCompare(currentToCompare);
}

希望能帮到像我这样的人。任何人,请让我知道,如果你觉得我是错的-或有其他办法。

先谢谢你。

我正在更新并返回传递给我的减速器的同一个对象。我通过在返回状态对象之前复制一个元素来修复这个问题,如下所示。

Object.assign({}, state)

要正确更新状态,不应该对数组进行变异。您需要创建数组的副本,然后用复制的数组设置状态。

const [deals, setDeals] = useState([]);
    

function updateDeals(deal) {
const newDeals = [...deals]; // spreading operator which doesn't mutate the array and returns new array
newDeals.push(deal);


// const newDeals = deals.concat(deal); // concat merges the passed value to the array and return a new array
// const newDeals = [...deals, deal] // directly passing the new value and we don't need to use push
    

setDeals(newDeals);
}