what-is-state-and-why-should-we-care-about-it-4o95

原始地址:https://dev.to/reedbarger/what-is-state-and-why-should-we-care-about-it-4o95

构建任何严肃的JavaScript应用程序,你必须理解一个让许多开发人员困惑的概念——状态。
##
[什么是状态?](https://dev.to#what-is-state)
如果你尝试学习React或Vue,你就会知道状态是这些库的一个重要概念。许多JavaScript开发人员尝试学习一个库,然后才弄清楚状态是什么以及如何处理它。
这是一个反向的方法。
状态存在于每个应用程序中,即使是使用纯JavaScript制作的应用程序也不例外。它不是JS库特有的概念;无论你打算制作哪个应用程序,都需要理解这个概念。库在你的应用程序中使用状态的概念是为了你自己的利益。
我们应用程序的状态是我们需要跟踪的所有数据。
为了更好地理解这是什么意思,让我们来看一个简单的应用程序以及用户如何与之交互:
这个应用程序的状态是什么?让我问你:这个应用程序本身需要跟踪哪些数据?
用户是登录用户还是游客。基于这些数据,用户消息会显示经过认证的消息“欢迎回来!”或未经认证的消息“您必须登录!”。所以认证状态是一个状态的一部分。
还有其他吗?注意到当用户是游客(未经认证)时,消息的颜色会从黑色变为红色。这可能代表一个错误状态。这是另一个状态的一部分。
##
[理解状态的挑战。](https://dev.to#the-challenge-of-understanding-state)
所有这些我们在应用程序中管理的小数据部分来自我们的应用程序状态。
当然,这并不是我们应用程序中的所有数据。我们可以举出更多的例子,但这给你提供了一个想法。
对于刚接触状态概念的开发人员来说,这是一个很难理解的问题。从最简单的待办事项应用到Facebook,当用户与应用程序交互时,这些交互的数据形成我们的状态。
对于我们的应用程序或任何应用程序来说,状态总是存在的。
这很可能是初学者无法理解状态的原因。状态存在于很多地方,很难给它一个准确的定义。但一旦你看到它的例子并知道它是什么,你就会意识到它无处不在。
##
[状态是随时间变化的数据](https://dev.to#state-is-data-over-time)
你可能会问为什么我们需要这个词"状态"。如果状态只是我们应用程序中的数据,为什么开发人员不把它称为应用程序数据呢?
我们之所以有一个特定的术语"状态",是为了描述我们的应用程序随着时间改变的方式。
例如,假设一个用户使用他们的姓名和电子邮件登录我们的应用程序。在用户这样做之前,我们将拥有与其登录后不同的状态(此时没有用户数据)。登录后,根据我们的应用程序需要,我们的状态将具有一些新值。例如,我们的应用程序可能需要为登录存储用户名、姓名和电子邮件。
##
[状态作为应用状态](https://dev.to#state-as-app-status)
如果"状态"这个词让你困惑,我喜欢将它与另一个外观相似的词"状态"进行比较。状态很重要,因为它告诉我们应用程序在任何时刻的状态。将其想象成电影的单个画面。
##
[状态管理的价值](https://dev.to#the-value-of-state-management)
到目前为止,我们知道状态是任何应用程序的一部分,但现在的问题是——我们该如何管理它?更重要的是,我们为什么想要管理它?
状态管理的好处是使我们的应用程序状态这个我们一直在谈论的看不见的数据集变得可见。我们通过将其变为一个数据结构来实现,我们可以在任何时候获取这些值(从状态读取)或更新这些值(设置状态)。
为了看到状态如何更好地管理,让我们看一下让状态存在,所以 to speak 的代码与我们如何管理它的代码之间的差异。让我们看一下我们在实际中看到的应用程序的代码:
即使您不理解所有的代码,也要知道我们的应用程序有一个简单的目标。
如果用户已登录,我们向其致以问候;如果是游客,则显示一个红色的错误消息。因此,根据给定的状态,我们显示一个消息或另一个消息。
我们的应用程序由JavaScript控制,类似于单页应用程序的结构(即React)。在我们的代码中,我们有一个render方法,它设置我们应用程序的HTML。然后,我们深入到DOM中找到ID为user-message的元素。我们还监听选项值的变化,通过监听change事件。然后,我们将所选值传递给checkAuth,以确定要显示的文本。
那么我们是如何管理状态的呢?此时我们并没有。我们知道这一点的方式是通过问一个问题:另一个开发人员看到我们的代码,能否通过查看我们的代码来识别出我们的状态?
如果我们查看checkAuth方法,可以看到有一些用户状态,但这并不明显。如果我们仔细看checkAuth中的条件,我们可能会猜测也有一个错误状态。但是,由于"错误"这个词没有出现在任何地方,它并不明显。我们不能指望任何人仅通过查看我们的代码就能轻松地确定此类信息。
管理状态在很大程度上是有清晰的代码声明它所做的事情。我们希望向其他开发人员传达我们关心的东西。因此,我们需要在一个更可读的位置呈现这些值。
除了我们的代码的可读性之外,我们可以根据状态所在的位置来判断我们是否正在管理状态。现在它并没有存在在一个明显的地方。其他开发人员可能不得不查看我们应用程序的所有部分才能确定状态。因此,我们的一部分状态位于我们的函数中,另一部分状态位于DOM中。它们是分散的。
让我们重写这段代码,以便我们要跟踪的状态值可以在任何开发人员容易找到的明显位置。最好将其存储在一个更集中的位置,而不是在我们的类的随机位置上。
##
[状态作为唯一的真实来源](https://dev.to#state-as-a-single-source-of-truth)
在我们重写任何东西之前,让我们引入一个帮助我们的想法。当我们编写我们的类或任何其他用于组织我们的应用程序的数据结构时,我们希望我们的状态管理作为我们的**唯一真实来源**。这意味着如果我们想要在任何时刻弄清楚我们应用程序的状态,我们将查看我们存储状态的位置。
许多JavaScript库(如React和Redux)用对象来管理状态是一种流行的方法。因此,在这个类中,我们的状态将存储在一个专用的状态对象中,在我们的构造函数的顶部创建它:
constructor() {
this.state = {};
}
如果任何开发人员想要知道我们正在跟踪哪些状态值,并且它们对于这个类来说很重要,他们可以在这里查看。
那么它们又是什么?我们关心的数据有哪些?我们关心是否有一个用户,因为这决定了我们要显示什么消息,我们还关心是否有一个错误。因此,isAuth(表示是否经过身份验证,适用于我们用户的状态)和error将成为状态对象的属性。isAuth将有两种状态,true或false。用户要么被认证了,要么没有被认证,error将存储错误消息作为字符串。
constructor() {
this.state = {
isAuth: false,
error: ""
};
}
现在,重新审视一下我们的状态对象作为我们唯一真实来源的想法,我们希望在任何给定的时刻依赖于我们在状态中存储的值。我们该如何做到这一点?
首先,我们希望设置状态或更新状态。这正是我们的checkAuth函数的用途。因此,在这里,我们不是立即将我们的应用程序状态放入DOM中,而是更新状态。如果用户为真,则在状态中isAuth应该为真。
##
[最佳实践:不可变地更新状态](https://dev.to#best-practice-update-state-immutably)
当我们更新状态时,我们要以不可变的方式进行。这意味着在进行任何更新之前,我们要复制先前的状态,以确保新状态不会引用旧的、不正确的值。状态更新应该始终是不可变的,因为新状态通常依赖于先前的状态。因此,我们不会这样写:
if (status === "auth") {
this.state.isAuth = true;
}
我们将使用扩展运算符对状态对象进行浅克隆,仅更新我们要更改的值:
if (status === "auth") {
this.state = { ...this.state, error: "", isAuth: true };
}
对于错误文本,也是同样的做法:
else if (status === 'unauth') {
this.state = { ...this.state, isAuth: false, error: "You must sign in!" };
}
在这里可能不太需要扩展剩余的状态,但当状态对象上有许多需要在状态更新之间保持不变的属性时,它是必需的。
现在我们可以完全摒弃userMessage的引用,不论是在checkAuth中还是在构造函数中。我们不需要深入到DOM中去改变我们的文本。
关于应用程序渲染的变化是什么?状态将决定UI,这意味着我们的应用程序必须根据状态更新来渲染,因此我们必须在更新状态后调用this.render():
constructor() {
this.state = {
isAuth: false,
error: ''
};
this.$authStatus = document.getElementById('auth-status');
this.$authStatus.addEventListener('change', event => {
// 使用checkAuth更新状态...
this.checkAuth(event.target.value);
// ...然后渲染应用程序来显示新状态
this.render();
});
}
现在有了我们的新状态,我们可以确定如何组织我们的渲染内容的结构。如果this.state.isAuth为true(如果我们有一个用户),我们将像以前一样显示我们的成功消息,但如果没有,我们将显示我们在错误状态中包含的错误消息。我们可以使用插值三元运算符来编写所有这些:
render() {
...
document.getElementById("root").innerHTML = `
<div>
${this.state.isAuth ? "Welcome back!" : this.state.error}
</div>
`;
}
使用解构的威力,我们可以通过从this.state获取我们需要的属性,使这个代码变得更加易读:
render() {
const { isAuth, error } = this.state;
...
document.getElementById("root").innerHTML = `
<div>
${isAuth ? "Welcome back!" : error}
</div>
`;
}
如果其他开发人员根据状态对象的内容不理解正在发生的情况,他们可以在这里的HTML中看到它的表示。在HTML中的状态反映了存储在状态对象中的状态。因此,这符合单一真实来源的原则。
最后,为了处理我们错误消息的红色文本,我们可以在封闭div上使用内联样式和运算符(&&)。对于color属性,如果我们有错误消息,如果它为真,则返回值'red':
render() {
const { isAuth, error } = this.state;
...
document.getElementById("root").innerHTML = `
<div style="color: ${error && "red"}">
${isAuth ? "Welcome back!" : error}
</div>
`;
}
这是我们的代码的最终版本,其中包含了我们所管理的状态:
##
[摘要](https://dev.to#summary)
我的挑战是让你看看我们的代码的起始版本,其中包含所有的DOM操作,然后与我们基于状态的第二个版本进行比较。对你来说哪个更有意义?哪个更容易阅读?为什么?
如果你需要消化我们在这里采取的方法和好处,请再次阅读这篇文章。但是如果你能看到以下想法的价值,那么它们应该是非常明确的:
使用状态变量/对象来声明和管理重要数据
为了可预测的结果,不可变地更新状态,
状态应该作为唯一真实来源
##
[在5周内成为React开发人员](https://dev.to#become-a-react-developer-in-5-weeks)
React很难。你不应该自己摸索。
我将我所知道的关于React的一切都放入了一门课程中,帮助您以最短的时间达到目标:
**介绍:React训练营** **这是我在开始学习React时希望自己拥有的课程。**
点击下方尝试React训练营:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值