我在react native中使用了xml解析器react-native-xml2js
,但是这个“插件”使用特定的函数来解析xml,但是我没有找到在函数中使用“ this”的正确方法,我已经尝试在回调中使用bind()
,但是使用绑定时无法按预期工作,它在执行后会填充我的变量,所以我不知道如何使用它,这是我的代码:>
state = { artcicles: null }
componentDidMount() {
fetch('http://example.com/rss.xml')
.then((response) => response.text())
.then((response) => {
parseString(response, function (err, result) {
this.setState({
articles: JSON.stringify(result.rss.channel[0].item)
})
console.log('RAW: ' + result.rss.channel[0].item);
console.log('THIS: ' + this.state.articles);
}.bind(this));
});
}
在开始时在this.state.articles
中调用render()
时显示null
,但是一秒钟后,它填充了articles
变量,但是此时应用程序在我尝试访问变量。
有什么想法吗?
谢谢。
答案 0 :(得分:1)
我可以帮助您观察一些东西。在React中,setState是异步的,因此setState之后的下一行代码将在将setState调用放入事件循环后立即执行。
您的真正问题是,那些console.log运行良好,您并不疯狂。它们只是在setState完成之前执行。
这里的秘诀是setState接受第二个参数,这是一个在状态更新后将执行的回调。您可以将所有以下逻辑放在该语句中。
这是一个采样器包:
this.setState({ dogs: 350 }, () => { console.log('The state has been updated.') })
setState()的第二个参数是可选的回调函数,将在setState完成并重新呈现组件后执行。通常,我们建议将componentDidUpdate()用于此类逻辑。
在您看来,它可能像这样:
componentDidMount() {
fetch('http://example.com/rss.xml')
.then((response) => response.text())
.then((response) => parseString(response, (err, result) =>
this.setState({
articles: JSON.stringify(result.rss.channel[0].item),
}, () => {
console.log('RAW:', result.rss.channel[0].item)
console.log('THIS:', this.state.articles)
}));
);
}
签出我在console.log上所做的修改。它也可以接受多个参数。
要输出的JavaScript对象的列表。这些对象的每个字符串表示形式都按列出的顺序附加在一起并输出。请注意,如果您在最新版本的Chrome和Firefox中记录对象,则在控制台上记录的内容是对该对象的引用,在调用控制台时,它不一定是对象的“值”。 log(),但它是单击对象时打开该对象时的值。
引用:https://developer.mozilla.org/en-US/docs/Web/API/Console/log
我特别喜欢该定义,因为它涉及实时引用的异步性质。一个函数本身可以是同步的,但是由于有调用堆栈和函数队列,您可以将无数个函数加载到队列中,并且它们会根据每个函数完成的时间以随机顺序完成,因为只有一个函数可以通过在主线程上一次通过调用堆栈。当然,对我们来说,这似乎是随机的顺序,但是实际上,假设所有这些函数都是确定性的,这实际上是所有这些函数在数学上最精确的路径。
快速前进到问题中的代码,除非您明确告知setState,否则它不会停止周围代码的执行。这就是回调的目的,如果您需要运行一些奖励代码。
在我们谈论setState
的同时,我还要提到您可以向其传递函数。想象一下,第二个参数回调是您在setState之后研究未来的方法。与之相反的是回顾过去,这是功能setState通过使您在前一个时间单位周围封闭而派上用场的地方。以前的状态也恰好是您要更新的任何内容的当前状态。
这里有一个采样器包:
this.setState((prevState) => {
// hello I like cats.gif
// we could run some fascinating code here
// as long as we return an object
console.log('rad')
return {
articles: [ ...prevState.articles, { new: 1, article: true }],
}
})
它为您提供了一个安全的窗口,可以通过更新来保证状态的完整性。我在那里展示了该示例,该示例将Array扩展为新Array并附加了一个对象,以演示类似于真实场景的情况,您可能需要在操作中引用当前状态。
在实际情况下,您可以对此进行改进,以利用Object文字的隐式返回(需要使用胖箭头语法):
this.setState(prevState => ({
articles: [ ...prevState.articles, { new: 1, article: true }],
})
希望这能帮助我们了解正在发生的情况。在React中,进行正式的变更管理过程很重要,因此每次获取或设置数据时,都需要注意谁在读取或写入数据以及从何处读取数据,例如程序的哪个功能和哪个部分。 React驯服JavaScript的方式是尝试迫使数据始终单向,不变和确定性地流动。
如果一切都以一种方式进行,则使reason about
的事情变得更容易。仅当您需要不变性并且喜欢确定性系统时,这才起作用。这意味着大多数函数都是以声明方式编写的,因此它们在函数开始时声明状态,进行填充,然后在函数结束时声明状态。
React使您认为自己主要是在编写纯JavaScript,但是实际上,它是使用先进先出技术来管理状态的,以避免可能在成千上万个组件试图同时写入状态时发生竞争的情况。当用户在浏览器中浏览键盘时,他们的脸部滚动会触发各种事件,我们不得阻塞主线程,否则用户体验不佳。
正式的变更管理流程意味着每次获取或设置数据时都应该使用一种正式模式。幸运的是,这些模式通常就是您编写纯JavaScript时将要执行的操作。反应性编程和不变性有助于驯服狂野的异步并发之神。
对不起,我们有点离题了,但是我必须为科学做这件事。
TLDR,
在this.setState()
之前,之中和之后的工作非常重要。这是一个特殊的函数,是Component Class上的class方法。我希望我已经帮助我们了解了它的几个秘密。
您试图在一个setState调用中执行两项操作。通常,您只需要设置状态即可:)您的预期用法很好。我们确实嵌套了一个额外的维度,但这很好,因为您只是在执行另一个操作。如果您要在回调函数中执行一系列功能,我不建议这样做。
注意声明的React文档
通常,我们建议将componentDidUpdate()用于此类逻辑。
它说为componentDidUpdate()
的原因是侦听状态更改,因此您可以在其中运行侦听某些条件然后执行操作的逻辑。它使您不必担心在调用站点的setState之后执行第二次操作。
想象一下,您在componentDidMount()
内做了 this.state.hasFetchedStuff = true ,然后在componentDidUpdate()
中做了类似的事情:
componentDidUpdate() {
if (this.state.hasFetchedStuff) {
this.triggerSomething()
}
}
这可以使您的componentDidMount不必在获取数据后就不必担心任何事情,这可能是很好的去耦和很好的关注点分离。
我也将此帖子也转换为中型文章,并添加了更多详细信息:https://medium.com/@agm1984/reacts-setstate-is-a-special-function-and-it-helps-with-asynchronous-concurrency-669eddbe3dd1
答案 1 :(得分:0)
在render()方法中,您可以使用inline If:
{this.state.articles && (
// Display articles
)}
当articles
停止为null时,&&之后的元素将出现,并且为null时,不会引发任何错误。
答案 2 :(得分:0)
可以使用空数组null
代替初始值[]
。这样,您的articles
状态变量就永远不会处于一致状态。另外,您可以避免在回调中使用手动绑定,而应使用箭头功能来保持当前范围。这样,您将拥有正确的闭包以使用this.state
。
parseString(response, (err, result) => {
this.setState({
articles: JSON.stringify(result.rss.channel[0].item)
})
});
答案 3 :(得分:0)
这个答案有些棘手
componentDidMount() {
fetch('http://example.com/rss.xml')
.then((response) => response.text())
.then((response) => {
parseString(response, function (err, result) {
this.setState({
articles: JSON.stringify(result.rss.channel[0].item)
})
console.log('RAW: ' + result.rss.channel[0].item);
setTimeout(() => {
console.log('THIS: ' + this.state.articles);
}, 1000);
}.bind(this));
});
}