Shiny中判断带req的reactive是否存在时分支逻辑异常问题
核心问题根源
Shiny的req()函数触发时不会让当前reactive返回NULL,而是直接抛出一个静默中断信号,终止当前整个reactive/输出的执行逻辑,不会继续运行后续代码,这是你所有问题的核心原因。
原代码顺序问题的解释
你最初的代码先判断!is.null(RAW()),只要RAW内部的req()未满足,执行到RAW()调用时就会直接触发中断,整个sumexp_all的reactive直接停止运行,根本不会走到后续判断FINAL文件的else分支,所以上传FINAL没有任何反应。
你调换两个判断的顺序后,只要FINAL文件存在,就不会触发RAW的调用,自然可以正常运行。
另外,is.null()判断reactive返回值的逻辑只适用于**该reactive无任何中断类语句、所有分支都会返回有效值(包括NULL)**的场景,内部包含req()的reactive不适用这个判断方法。
tryCatch版本报错的解释
你写的tryCatch版本报错有两个原因:
req()抛出的是shiny.silent.error类型的特殊中断,不属于普通error,你只捕获普通error的话,很多场景下无法捕获到req的中断,导致checkerror变量未被正常赋值,长度为0,执行if(checkerror != "empty")时,条件值长度为0,就会触发argument is of length zero的错误。- 你在判断
checkerror != "empty"为真后,又二次调用了RAW(),哪怕第一次调用捕获了错误,第二次调用依然会触发req的中断,等于白做了异常捕获。
最小可复现示例的问题验证
你提供的示例里,stepb()内部包含req(stepa()),未点击按钮时stepa()无值,stepb()调用会直接触发中断:
- 执行
is.null(stepb())时直接中断,不会返回TRUE/FALSE,所以output$printcheck无内容 fin()调用stepb()时直接中断,不会走到else分支读取input$text,所以output$checkfin无内容,和你的业务场景问题完全一致。
解决方案
方案1(最优,最简单)
优先判断无中断风险的分支,也就是先判断FINAL文件是否上传,再处理RAW的逻辑,和你之前调整顺序后的写法一致:
sumexp_all = reactive({ if(!is.null(input$finalsumexpinput)){ readRDS(file = input$finalsumexpinput$datapath) }else if(!is.null(tryCatch(RAW(), shiny.silent.error = function(e) NULL))){ list(sumexp_data = RAW()$sumexp_data, sumexp_data_mean = RAW()$sumexp_data_mean, replicates = RAW()$replicates) }else{ NULL } })
方案2(需要先判断RAW的场景)
正确捕获所有类型的中断,且只调用一次RAW(),用临时变量存储返回值再做判断:
sumexp_all = reactive({ # 捕获所有中断、错误,无有效值则返回NULL raw_val <- tryCatch( RAW(), shiny.silent.error = function(e) NULL, error = function(e) NULL, interrupt = function(i) NULL ) if(!is.null(raw_val)){ list( sumexp_data = raw_val$sumexp_data, sumexp_data_mean = raw_val$sumexp_data_mean, replicates = raw_val$replicates ) }else if(!is.null(input$finalsumexpinput)){ readRDS(file = input$finalsumexpinput$datapath) }else{ NULL } })
最小可复现示例修正代码
把fin的reactive按上述逻辑修改即可正常运行:
fin = reactive({ stepb_val <- tryCatch( stepb(), shiny.silent.error = function(e) NULL, error = function(e) NULL ) if(!is.null(stepb_val)){ stepb_val }else{ input$text } })
内容的提问来源于stack exchange,提问作者Fabio DR
相关产品推荐
相关产品推荐

