☰
Openblocks 临时状态(Temporary State)完全指南:setValue / setIn 与计数器实战
2026/10/11 20:44:08 网站建设 项目流程
  • 低代码
  • 后端
  • 前端
  • 开发工具

【免费下载链接】openblocks

🔥 🔥 🔥 The Open Source Retool Alternative

项目地址:https://gitcode.com/gh_mirrors/op/openblocks
点击查看免费下载

临时状态(Temporary State)是 Openblocks 中用于在应用内存储和引用局部数据的轻量级机制:它的值只存在于当前应用的一次加载会话中,每次加载或刷新应用都会重置回初始值,非常适合跟踪用户交互过程中的临时变量、存放"仅运行期需要、无需落库"的数据,以及充当内置属性(如{{table.selectedRow}}、{{select.value}})无法覆盖场景下的临时属性。读完本文你将掌握临时状态的创建、初始值配置、setValue()/setIn()两种赋值方法,并能通过事件处理器与 JavaScript 查询两条路径实现一个完整的自增计数器。

本文对应的官方文档为 docs/build-apps/write-javascript/temporary-state.md,核心实现位于 temporaryStateComp.tsx。

什么是临时状态:会话级数据的存放区

临时状态可以理解为应用内的一块"便签纸"——你可以随时写入、改写和读取它,但它的生命周期只跟随当前应用页面:

  • 每次加载或刷新应用,临时状态的值都会被重置为你在编辑器中设定的初始值;
  • 刷新前的运行期写入值不会持久化,也不会跨页面、跨应用保留;
  • 它保存的数据是任意合法的 JSON 值(对象、数组、字符串、数字、布尔值等),这与源码中初始值控件jsonValueStateControl(null)的定义一致(见 temporaryStateComp.tsx)。

从底层实现看,临时状态是作为"底部资源"(BottomRes)挂载在应用根组件上的:TemporaryStateListComp通过bottomResListComp生成器注册到根组件tempStates字段(见 rootComp.tsx),编辑器在运行时按名称查找并暴露其value(见 rootComp.tsx)。这种"只在运行时生效、仅持久化初始值"的设计,正是withTmpState机制中"只保存 defaultValue"(only save defaultValue)的体现(见 codeStateControl.tsx)。

典型使用场景

官方文档给出的临时状态适用场景包括:

  1. 跟踪用户交互过程中的临时变量值,例如统计按钮点击次数、记录当前步骤等;
  2. 仅在运行期存放数据而不写入数据库,避免为一次性操作创建持久化存储;
  3. 充当临时属性,当 Openblocks 内置属性(如{{table.selectedRow}}、{{select.value}})无法满足你的用例时,用临时状态承接中间数据。

注意区分:临时状态只在当前应用、当前会话内有效。若需要跨应用保存和访问数据,应改用localStorage,而不是临时状态。

创建临时状态

在查询编辑器(Query Editor)中,点击+ New,选择Temporary state,即可创建一个新的临时状态。

创建后,你可以:

  • 重命名:为临时状态取一个符合语义的名字(默认命名前缀为state,源码中bottomResListComp的namePrefix参数即"state",见 temporaryStateComp.tsx);
  • 设置初始值:在属性面板的 "Init value" 输入框中填写初始值。该值可以是任意合法 JSON 值,编辑器提示语为 "The initial Value stored in the temporary state can be any valid JSON Value."(见 en.ts)。

初始值支持表达式绑定,例如可以直接写{{ input1.value }}、一个对象字面量或数组,在运行时作为临时状态的起点。

设置状态值:setValue 与 setIn

临时状态暴露两个赋值方法:setValue()与setIn()。它们可以在 JavaScript 查询中直接调用,也可以在事件处理器中作为Set temporary state动作使用。从实现上看,这两个方法通过withMethodExposing注册为组件的可执行方法(见 temporaryStateComp.tsx)。

setValue(value):整体替换

setValue()用于直接改变临时状态的整个值,签名为state.setValue(value),其中value可以是任意 JSON 值:

// state.setValue(value: any) state.setValue(3) state.setValue(input1.value)

底层实现非常简单——直接调用状态控件的change方法写入新值:

// 源码节选:temporaryStateComp.tsx execute: async (comp, params) => { comp.children.value.change(params?.[0]); },

调用setValue后,{{ state.value }}会立即反映新值,并触发依赖它的组件与查询重新计算。

setIn(path, value):按路径修改

当临时状态的初始值是一个对象或数组时,可以用setIn()修改指定路径上的值,而无需整体替换。签名为state.setIn(path, value),其中path是由键名或索引组成的数组,并且只有路径中的最后一项会被修改。

官方文档示例(初始值 state2):

// 初始值 state2 如下 { girl: { name: "Lucy", age: 18, city: { name: "New York" } }, boy: { name: "Bob", age: 21, city: { name: "Los Angeles" } } } // 修改指定路径的值 // state.setIn(path, any value) // path: 由键或索引组成的数组,只有路径最后一项会被修改 state2.setIn(['girl', 'city'], { name: 'Seatle' }) state2.setIn(['boy', 'age'], 18) // 修改数组值 // init value = ["hello", "world"] state2.setIn([1], "foo") // 结果为 ["hello", "foo"]

setIn的源码实现揭示了几个重要约束(见 temporaryStateComp.tsx):

  1. path 必须是数组,且每个元素只能是字符串(键名)或数字(数组索引),否则抛出pathTypeError("Path must be either a string or an array of values");
  2. 当前值必须是普通对象或数组,否则抛出unStructuredError("Unstructured data {prev} can't be updated by {path}")——也就是说,若当前值退化为字符串、数字等标量,setIn无法工作;
  3. 底层使用_.set(_.cloneDeep(prev), path, value)实现:先深拷贝原值,再按路径写入新值,最后整体写回,因此原值不会被原地修改,天然具备不可变性。

在事件处理器中调用

除了 JavaScript 查询,你还可以在**事件处理器(Event Handlers)**中调用这两个方法:

  1. 为组件(如按钮)添加事件处理器;
  2. 选择动作Set temporary state;
  3. 选择目标临时状态和方法(setValue或setIn),按需传入参数。

事件处理器的这个动作由SetTempStateAction实现:它会列出当前应用中所有临时状态供选择,然后以name.method()的形式动态调用其暴露方法(见 setTempStateValueAction.tsx 与 executeCompAction.tsx)。在属性面板中,动作会显示为state1.setValue()这样的调用形式,参数按方法的参数类型(如JSONValue)自动渲染输入框。

实战示例:自增计数器

下面通过一个经典的自增计数器,完整走一遍临时状态的使用流程。计数器用于跟踪按钮被点击的次数:每次点击,文本组件中的数字加一。

方式一:事件处理器 + Set temporary state

按以下步骤构建:

  1. 添加组件:拖入一个按钮组件button1和一个文本组件text1;

  2. 创建临时状态:新建临时状态state1,将其初始值设为0;

  3. 绑定文本:将text1的显示文本绑定为{{state1.value}}。

  4. 添加事件处理器:为button1添加事件处理器,选择动作Set temporary state、方法setValue,并把值设置为{{state1.value + 1}}。

  5. 点击验证:运行应用,每点击一次按钮,text1中的数字就增加 1。

方式二:JavaScript 查询

同样的效果也可以通过 JavaScript 查询实现:

  1. 新建查询:添加一个新查询,选择Run JavaScript code(即js类型查询,见 ResCreatePanel.tsx);

  2. 编写代码:在查询中写入以下代码,并将查询设为手动触发(Manual):

    state1.setValue(state1.value + 1)
  3. 挂接事件处理器:为button1添加事件处理器,动作选择Run query并指向query1。

完成后点击Increment counter按钮,即可看到与方式一完全相同的结果。

两种方式的差别在于:方式一在事件处理器中直接调用状态方法,无需额外创建查询;方式二则适合需要在赋值前后叠加更多逻辑(如计算、条件分支、调用其他查询)的场景。

进阶:理解临时状态的重置与生命周期

临时状态之所以"临时",根源在于withTmpState的求值机制(见 codeStateControl.tsx):

  • 临时状态在 DSL(应用定义)中只持久化初始值(defaultValue),运行时的value字段不写入持久化数据;
  • 每次应用加载,运行时值由求值器重新计算为初始值,因此刷新即重置;
  • setValue/setIn的写入动作仅作用于当前运行会话的内存状态,不会改变 DSL 中的初始值配置。

这意味着你完全可以把临时状态当作"应用运行期的工作变量",无需担心污染应用定义或数据库。结合withMethodExposing的统一方法暴露机制(见 withMethodExposing.tsx),临时状态的方法调用与组件、查询的方法调用遵循同一套事件处理器体系,学习成本极低。

如果你还需要更复杂的派生计算,可进一步阅读 Openblocks 的 transformers 与 data responder 相关文档,它们与临时状态一起构成了应用内数据编排的完整工具链。

  • 低代码
  • 后端
  • 前端
  • 开发工具

【免费下载链接】openblocks

🔥 🔥 🔥 The Open Source Retool Alternative

项目地址:https://gitcode.com/gh_mirrors/op/openblocks
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询