状态管理如何运作?原生 JavaScript 中的简单状态管理

2025-05-28

状态管理如何运作?原生 JavaScript 中的简单状态管理

原生 JavaScript 中极其简单的状态管理。
你用 Redux、MobX 甚至 React Hooks 都好几年了,却对状态管理的工作原理以及它为什么这样工作一无所知?我将向你展示状态管理中极其简单的底层工作,无需任何优化或其他花哨的功能。

我们将构建一个包含脚本标签的极其简单的纯 HTML 页面。

<!DOCTYPE html>
<html>
  <head>
    <title>State Management in Vanilla JS</title>
  </head>

  <body>
    <div id="app"></div>

    <script>
      // 
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

现在让我们编写一些 JavaScript。

注意: TL;DR; 在下面⏬

const App = function _App() {  
  return `
    <h1>Hello Vanilla JS</h1>
    <div>Example of state management in Vanilla JS</div>
  `;
}
document.getElementById("app").innerHTML = App();
Enter fullscreen mode Exit fullscreen mode

我可以简单地声明为

const App = function() { // ...
// or
const App = () => { // ...
Enter fullscreen mode Exit fullscreen mode

但我没这么做是有原因的,稍后我会解释。现在,让我们创建一些状态

App.state = {
  count: 0,
  increment: () => {
    App.state.count++;
  }
};
Enter fullscreen mode Exit fullscreen mode

作为 App 函数的属性创建的简单状态。😉

等等!你能做到吗? 😲

是的,JavaScript 中的所有内容都是对象,从技术上讲,你甚至可以对字符串和数字进行对象化。这就是为什么像"hello world".toUppercase()and这样的方法(12).toFixed(2)能够正常工作。但是编译器不允许你在字符串或数字上定义自己的属性。

现在 App 已经具有状态,我们将整合状态并在文件末尾添加一个点击事件监听器。

`
  <h1>${_App.state.count}</h1>
  <button id="button">Increase</button>
`
// ...
document.getElementById("app").innerHTML = App();
// On Click Function
document
  .getElementById("button")
  .addEventListener("click", App.state.increment);
Enter fullscreen mode Exit fullscreen mode

请注意,我访问 App 内部的方法既不是this也不是 ,App而是_App。这被称为“命名函数表达式”。

命名函数表达式有两个特殊之处:

  1. 它允许函数在内部引用自身。
  2. 它在函数外部是不可见的。

即使我在下面做了类似的事情,代码也不会中断。

const Component = App;
App = null;
document.getElementById("app").innerHTML = Component();
Enter fullscreen mode Exit fullscreen mode

即使 App 被重新赋值给 Component,然后又被置为 null,函数本身仍然保持不变,并在本地以 _App 的形式引用自身,因此不受影响。这和this其他所有 OOP 编程语言中的“ ”一样(不过我们都知道thisJavaScript 是如何运作的)😅。

现在尝试运行它(只需双击 index.html 文件)。注意,点击函数不起作用!🙄 这是因为 UI 没有反映最新状态,让我们通过重新渲染元素来解决这个问题。这可以通过在状态更新后再次运行这段代码来实现。

document.getElementById("app").innerHTML = App();
// On Click Function
document
  .getElementById("button")
  .addEventListener("click", App.state.increment);
Enter fullscreen mode Exit fullscreen mode

由于此代码将会重复,我们将其提取到函数中

const updateTree = () => {
  document.getElementById("app").innerHTML = App();
// On Click Function
  document
    .getElementById("button")
    .addEventListener("click", App.state.increment);
}
Enter fullscreen mode Exit fullscreen mode

现在添加一个 setState 函数

const setState = (callback) => {
  callback();
  updateTree(); // extracted function
}
Enter fullscreen mode Exit fullscreen mode

并将增量函数更新为

increment: () => {
  // Call our set state function
  setState(() => App.state.count++);
}
Enter fullscreen mode Exit fullscreen mode

现在我们的应用已经按预期运行了。就这样!原生 JavaScript 中死气沉沉的状态管理就到此为止了。然而,如果只是照原样使用,会被认为是一个糟糕透顶的框架,原因并非在于它缺乏任何花哨的功能,而是因为它的优化很差,实际上它根本就没有优化,不过我在文章开头说“……没有任何优化或其他花哨的功能”的时候,你应该已经明白了。

要做的事情,

  1. 不应使整个应用程序反映一个简单的变化。
  2. 一旦我们更新以反映状态,附加到 DOM 的所有事件监听器都不应丢失,并且我们不应该在其位置添加新的事件监听器。
  3. 不受状态影响且未改变的 DOM 元素不应被强制更改。更改应尽可能小

因此,我们将对我们的应用程序进行一些优化,就像 React 和类似的库/框架在下一篇文章中所做的那样。

TL;DR;

这是我们迄今为止编码的完整 HTML 文件。

<!DOCTYPE html>
<html>
  <head>
    <title>State Management in Vanilla JS</title>
  </head>

  <body>
    <div id="app"></div>

    <script>
      const App = function _App() {
        return `
          <h1>Hello Vanilla JS!</h1>
          <div>
            Example of state management in Vanilla JS
          </div>
          <br />
          <h1>${_App.state.count}</h1>
          <button id="button">Increase</button>
        `;
      };

      App.state = {
        count: 0,
        increment: () => {
          setState(() => App.state.count++);
        }
      };

      const setState = (callback) => {
        callback();
        updateTree(); // extracted function
      }

      const updateTree = () => {
        document.getElementById("app").innerHTML = App();
        document
          .getElementById("button")
          .addEventListener("click", App.state.increment);
      };

      updateTree();
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

更新:

  1. (2021 年 3 月 13 日)添加了setState函数,修复了一些拼写错误,并添加了命名函数表达式的链接。
文章来源:https://dev.to/vijaypushkin/dead-simple-state-management-in-vanilla-javascript-24p0
PREV
使用这些扩展和工具成为 VS Code 忍者 [2020] 附赠
NEXT
那些你从未使用过的 HTML 元素