ToolJet 动作参考:Set variable 动作的配置与底层实现原理
【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet
本篇文章聚焦 ToolJet 中的Set variable(设置变量)动作,介绍如何通过该动作创建自定义变量并赋值,涵盖 Key / Value / Debounce 三个选项的完整配置说明,并结合frontend仓库源码剖析该动作从事件触发、值解析到状态更新的底层调用链。读完本文,你将能够在 ToolJet 应用中熟练使用 Set variable 动作维护跨组件共享的状态,并能在 RunJS 查询中以代码方式动态写入变量。
本文基于 ToolJet 仓库中 version-2.50.0-LTS 的 Set variable 文档 展开,并辅以 frontend 源码 进行原理层面的印证。
Set variable 动作能做什么
Set variable 是一个事件动作(Event Action),它允许你创建一个自定义变量,并为该变量赋予一个value。创建后的变量可以在整个应用范围内被读取和使用,是 ToolJet 应用中实现组件间数据传递、跨页面状态共享的基础手段之一。
在 ToolJet 的响应式体系中,变量写入后会自动触发依赖它的表达式重新计算,因此非常适合承载诸如「当前选中项」「主题模式」「用户偏好」「分页状态」等需要被多个组件或查询共享的临时状态。
该动作与配套的 Unset variable(删除变量)动作 一起构成了变量生命周期的「写」与「删」两个端点,而变量读取则统一通过 Inspector 面板或{{variables.变量名}}表达式完成。
选项详解
在事件的「动作」下拉框中选择Set variable后,会出现以下三个配置项:
| 选项 | 说明 |
|---|---|
| Key | 变量名(String 类型),通过该名称即可访问变量的值 |
| Value | 变量的值,可以是字符串、数字、布尔表达式、数组或对象 |
| Debounce | 防抖时间,默认留空;填写数值可指定动作延迟执行的毫秒数,例如300 |
Key:变量名即访问句柄
Key是变量的唯一标识名,类型为字符串。变量创建后,你可以通过 Inspector 面板或表达式{{variables.<key>}}来访问它的值。例如设置Key = mode,之后便可用{{variables.mode}}读取。Key 的命名应遵循 JavaScript 标识符习惯(建议使用驼峰或下划线命名),以方便在表达式中直接引用。
Value:支持任意 JavaScript 可求值类型
Value字段支持的类型非常宽泛,包括:
- 字符串:如
"active"、"dark"; - 数字:如
42、3.14; - 布尔表达式:如
{{components.checkbox1.value === true}}、1 > 0; - 数组:如
[1, 2, 3]或{{queries.getData.data}}; - 对象:如
{ name: 'ToolJet', version: '2.50.0' }。
由于 Value 字段支持模板表达式({{ }}),你可以把任意组件属性、查询返回值、全局设置等动态来源直接赋值给变量,从而实现「快照」式的状态缓存。这一点与源码实现高度一致:在事件执行阶段,key和value都会先经过getResolvedValue做求值解析,再写入状态(详见下文「底层原理」小节)。
Debounce:延迟执行与事件节流
Debounce字段默认留空,此时动作立即执行;一旦填入数值,动作会在该毫秒数之后才执行,例如300表示 300ms 后执行。它适用于:
- 配合输入类组件事件,避免高频触发导致频繁写入变量;
- 将多个相近时刻触发的事件合并为一次写入,降低不必要的依赖重算开销。
在源码层面,动作执行入口本身就被节流包装:executeAction使用了debounce包裹(见 eventsSlice.js),而防抖时间取自事件配置:const debounceTime = event?.event?.debounce || event?.debounce;(见 utils.js),最终以Number(debounceTime)作为延迟毫秒数。可以看到,文档中描述的「延迟毫秒数」在实现中正是被转换为setTimeout语义的数值参数。
典型使用场景与配置步骤
Set variable 动作通常挂在组件的某个事件上(如按钮的On Click、文本框的On Change、表格的On Row Selected等),具体步骤为:
- 在画布中选中目标组件,打开右侧「属性」面板,找到对应事件(如
On Click); - 点击「+ 添加」创建处理器,在弹窗中选择动作Set variable;
- 填写
Key,例如selectedRow; - 在
Value中填入表达式,例如{{components.table1.selectedRow}},把表格当前选中行快照到变量中; - (可选)在
Debounce中填写如300,为写入增加防抖; - 保存并发布应用后,即可在其他组件或查询中通过
{{variables.selectedRow}}读取该值。
从 RunJS 查询中触发
除了通过可视化事件配置,Set variable 动作也可以直接在RunJS 查询中以 JavaScript 代码触发,两者写入的是同一个变量存储。相关语法参考 Run actions from RunJS 指南:
// 创建变量并赋值 actions.setVariable('mode', 'dark') // 删除变量 actions.unSetVariable('mode') // 设置后立即读取(同步返回) actions.setVariable('number', 1) return actions.getVariable('number') // 页面级变量(page 作用域) actions.setPageVariable('pageKey', 100) return actions.getPageVariable('pageKey')需要注意,actions.setVariable('变量名', 值)的值参数可以是任意 JavaScript 值(字符串、数字、布尔、数组、对象),并且在 RunJS 上下文中写入是同步生效的——调用后在同一段 RunJS 代码里即可用getVariable读回,这为「先写入、再使用」的脚本逻辑提供了便利。
工具链对这类代码有专门的静态分析支持:frontend中的 scriptAnalysis.ts 定义了ACTION_FN_BUCKETS,把actions.setVariable(...)归类为「变量写入(variableWrites)」,把actions.getVariable(...)归类为「变量读取(variableReads)」,从而在 Dependency Viewer 中呈现变量的读写依赖关系。
底层原理:从事件到状态更新的调用链
Set variable 动作的执行核心位于前端状态管理层,其完整链路如下:
1. 事件分发:所有事件动作都经由executeAction(防抖包装)统一入口分发,见 eventsSlice.js。入口会先检查event.disabled与event.runOnlyIf条件,不满足则直接跳过。
2. 动作匹配与值解析:当event.actionId === 'set-custom-variable'时,执行以下逻辑(见 eventsSlice.js):
case 'set-custom-variable': { const { setVariable } = get(); const key = getResolvedValue(event.key, customVariables, moduleId); const value = getResolvedValue(event.value, customVariables, moduleId); setVariable(key, value, moduleId); return Promise.resolve(); }key与value都会先经过getResolvedValue求值——这正是文档中「Value 可以是布尔表达式、数组或对象」的底层实现依据:任何{{ }}模板表达式都在此处被解析为实际值。
3. 状态写入与依赖传播:setVariable的实现位于 resolvedSlice.js:
setVariable: (key, value, moduleId = 'canvas') => { // 同步写入,保证同一 RunJS 上下文中可立即读回 set((state) => { state.resolvedStore.modules[moduleId].exposedValues.variables[key] = value; }, false, 'setVariable'); // 依赖更新被延迟调度,与同批次 setVariable 调用合并 scheduleDependencyUpdate(`variables.${key}`, moduleId); get().rebuildVariableHints(moduleId); },可以看到三个关键设计:
- 同步写入:变量值直接写入
exposedValues.variables[key],写入即刻完成,因此 RunJS 中setVariable后紧跟getVariable能立即读到新值; - 延迟依赖更新:
scheduleDependencyUpdate('variables.<key>')采用微任务批次合并机制,将同一次事件循环内的多次变量写入合并为一次依赖级联重算,避免性能抖动; - 提示重建:
rebuildVariableHints会同步更新代码补全/Inspector 中的变量提示列表。
从源码结构看,应用级变量与页面级变量(setPageVariable)分别存储在同一exposedValues下的variables与page命名空间中,且共享同一套「同步写入 + 依赖调度 + 提示重建」机制,这就是为什么在 Inspector 中能同时看到variables与page.variables两类条目。
变量的读取与生命周期管理
- 读取:变量创建后,可在任何支持表达式的字段中通过
{{variables.<key>}}访问;在 RunJS 中则用actions.getVariable('<key>')读取。 - 删除:使用 Unset variable 动作 删除指定变量,其
Key与Debounce选项与 Set variable 一致;对应源码为unsetVariable,会执行delete exposedValues.variables[key]并从依赖图中移除该节点(见 resolvedSlice.js)。 - 持久性:Set variable 创建的变量为运行时变量,随应用会话存在,应用刷新后会重置;若需要跨会话保存的数据,应改用其他持久化机制(如 ToolJet Database 或后端 API),不要将 Set variable 当作持久化存储使用。
小结
Set variable 是 ToolJet 应用中最基础也最常用的事件动作之一:通过Key定义变量名、Value支持任意可求值类型、Debounce控制执行时机;在可视化事件与 RunJS 两种触发方式下,最终都会落到同一套「同步写入 + 依赖调度」的状态管理实现上。理解其选项语义与底层调用链(eventsSlice.js → resolvedSlice.js),可以帮助你在构建多组件联动的复杂应用时,更合理地规划变量结构与读写时机。
【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考