挂载组件时将端口Redux状态更改为组件状态(无需GET请求)

时间:2019-02-24 08:41:23

标签: javascript reactjs redux

我在React / Redux应用程序中有一个用于更新信息的表格-因此需要使用当前数据预先填充字段。

在安装组件之前,表单的数据已经处于Redux状态。

当前,在library(plotly) library(shiny) library(htmlwidgets) js <- c( "function(el, x, inputName){", " var id = el.getAttribute('id');", " var d3 = Plotly.d3;", " el.on('plotly_restyle', function(evtData) {", " var out = {};", " d3.select('#' + id + ' g.legend').selectAll('.traces').each(function(){", " var trace = d3.select(this)[0][0].__data__[0].trace;", " out[trace.name] = trace.visible;", " });", " Shiny.setInputValue(inputName, out);", " });", "}") YNElement <- function(idx){sprintf("YesNo_button-%d", idx)} ui <- fluidPage( fluidRow( column(2, h5("Keep/Drop choices linked to colorscheme 1"), uiOutput('YNbuttons') ), column(8, plotlyOutput("plot1") ), column(2, h5('Switch grouping'), actionButton(inputId = 'Switch', label = icon('refresh'), style = "color: #f7ad6e; background-color: white; border-color: #f7ad6e; height: 40px; width: 40px; border-radius: 6px; border-width: 2px; text-align: center; line-height: 50%; padding: 0px; display:block; margin: 2px") ), style = "margin-top:150px" ), verbatimTextOutput("tracesPlot1"), verbatimTextOutput("tracesPlot2") ) server <- function(input, output, session) { values <- reactiveValues(colors = T, NrOfTraces = length(unique(mtcars$cyl))) output$plot1 <- renderPlotly({ print('plotting!') if(values$colors) { colors <- c('red', 'blue', 'green') } else {colors <- c('black', 'orange', 'gray')} p1 <- plot_ly() p1 <- add_trace(p1, data = mtcars, x = ~disp, y = ~mpg, type = 'scatter', mode = 'markers', color = ~as.factor(cyl), colors = colors) p1 <- layout(p1, title = 'mtcars group by cyl with switching colors') p1 <- plotly_build(p1) if(values$colors) { for(i in seq_along(p1$x$data)){ p1$x$data[[i]]$visible <- values$legenditems[[p1$x$data[[i]]$name]]} } p1 %>% onRender(js, data = "tracesPlot1") }) observeEvent(input$Switch, { values$colors <- !values$colors }) ##### THIS BLOCK links buttons -> plot, but causes it to render all over again ### this interaction is what I would like to replace by javascript observeEvent(values$dYNbs_cyl_el, { legenditems <- values$dYNbs_cyl_el legenditems[which(legenditems == FALSE)] <- 'legendonly' legenditems[which(legenditems == TRUE )] <- 'TRUE' names(legenditems) <- sort(unique(mtcars$cyl)) values$legenditems <- as.list(legenditems) }) observeEvent(values$NrOfTraces, { values$dYNbs_cyl_el <- rep(T,values$NrOfTraces) names(values$dYNbs_cyl_el) <- sapply(1:values$NrOfTraces, function(x) {YNElement(x)}) }) output$YNbuttons <- renderUI({ req(values$NrOfTraces) lapply(1:values$NrOfTraces, function(el) { YNb <- YNElement(el) if(values$dYNbs_cyl_el[[YNb]] == T ) { div(actionButton(inputId = YNb, label = icon("check"), style = "color: #339FFF; background-color: white; border-color: #339FFF;height: 34px; width: 34px; border-radius: 6px; border-width: 2px; text-align: center; line-height: 50%; padding: 0px; display:block; margin: 2px")) } else { div(actionButton(inputId = YNb, label = icon("times"), style = "color: #ff4d4d; background-color: white; border-color: #ff4d4d;height: 34px; width: 34px; border-radius: 6px; border-width: 2px; text-align: center; line-height: 50%; padding: 0px; display:block; margin: 2px")) } }) }) flipYNb_FP1 <- function(idx){ YNb <- YNElement(idx) values$dYNbs_cyl_el[[YNb]] <- !values$dYNbs_cyl_el[[YNb]] } observe({ lapply(1:values$NrOfTraces, function(ob) { YNElement <- YNElement(ob) observeEvent(input[[YNElement]], { flipYNb_FP1(ob) }, ignoreInit = T) }) }) observeEvent(input$tracesPlot1, { listTraces <- input$tracesPlot1 values$legenditems <- listTraces ## this line would save the legend status even if we remove the observer for the values$dYNbs_cyl_el list listTracesTF <- gsub('legendonly', FALSE, listTraces) listTracesTF <- as.logical(listTracesTF) lapply(1:values$NrOfTraces, function(el) { if(el <= length(listTracesTF)) { YNb <- YNElement(el) if(values$dYNbs_cyl_el[[YNb]] != listTracesTF[el]) { values$dYNbs_cyl_el[[YNb]] <- listTracesTF[el] } } }) }) output$tracesPlot1 <- renderPrint({ unlist(input$tracesPlot1) }) output$tracesPlot2 <- renderPrint({ unlist(values$legenditems) }) } shinyApp(ui, server) 生命周期内,发送了axios GET请求以再次从数据库中检索信息,并将其加载到redux状态。

此方法工作正常,但是我希望避免附加/冗余的GET请求,因为信息已经处于redux状态。

如何在加载时将redux状态移植到组件的状态,以便填充输入字段(不需要GET请求)?

组件代码如下。

library(plotly)
library(shiny)
library(htmlwidgets)

# js <- c(
#   "function(el, x, inputName){",
#   "  var id = el.getAttribute('id');",
#   "  var d3 = Plotly.d3;",
#   "  el.on('plotly_restyle', function(evtData) {",
#   "    var out = {};",
#   "    d3.select('#' + id + ' g.legend').selectAll('.traces').each(function(){",
#   "      var trace = d3.select(this)[0][0].__data__[0].trace;",
#   "      out[trace.name] = trace.visible;",
#   "    });",
#   "    Shiny.setInputValue(inputName, out);",
#   "  });",
#   "}")


js2 <- c(
"function(el, x, inputName){",
"  var id = el.getAttribute('id');",
"  if(id == inputName){",
"    var data = el.data;",
"    $('[id^=btn]').on('click', function() {",
"      var index = parseInt(this.id.split('-')[1]);",
"       var trace = index -1; ",
"      var v0 = data[trace].visible || true;",
"      var v = v0 == true ? 'legendonly' : true;",
"      Plotly.restyle(el, {visible: v}, [trace]);",
"    });",
"  }",
"}")


YNElement <-    function(idx){sprintf("btn-%d", idx)}

ui <- fluidPage(
  fluidRow(
    column(2,
           h5("Keep/Drop choices linked to colorscheme 1"),
           uiOutput('YNbuttons')
    ),
    column(8,
           plotlyOutput("plot1")
    ),
    column(2,
           h5('Switch grouping'),
           actionButton(inputId = 'Switch', label = icon('refresh'), style = "color: #f7ad6e;   background-color: white;  border-color: #f7ad6e;
                        height: 40px; width: 40px; border-radius: 6px;  border-width: 2px; text-align: center;  line-height: 50%; padding: 0px; display:block; margin: 2px")
           ), style = "margin-top:150px"
    ),
  verbatimTextOutput("tracesPlot1"),
  verbatimTextOutput("tracesPlot2")

  )

server <- function(input, output, session) {
  values <- reactiveValues(colors = T, NrOfTraces = length(unique(mtcars$cyl)))

  output$plot1 <- renderPlotly({
    print('plotting!')

    values$legenditemNames <- sort(unique(mtcars$cyl))

    if(values$colors) { colors <- c('red', 'blue', 'green') } else {colors <- c('black', 'orange', 'gray')}
    p1 <- plot_ly()
    p1 <-  add_trace(p1, data = mtcars, x = ~disp, y = ~mpg, type = 'scatter', mode = 'markers', color = ~as.factor(cyl), colors = colors)
    p1 <- layout(p1, title = 'mtcars group by cyl with switching colors')
    p1 <- plotly_build(p1)

    if(values$colors) { for(i in seq_along(p1$x$data)){
      p1$x$data[[i]]$visible <- values$legenditems[[p1$x$data[[i]]$name]]}
    }
     p1 %>% onRender(js2, data = "tracesPlot1")
  })


  observeEvent(input$Switch, { values$colors <- !values$colors    })

  ##### THIS BLOCK links buttons -> plot, but causes it to render all over again
    # observeEvent(values$dYNbs_cyl_el, {
    #   legenditems <- values$dYNbs_cyl_el
    #   legenditems[which(legenditems == FALSE)] <- 'legendonly'
    #   legenditems[which(legenditems == TRUE )] <- 'TRUE'
    #   names(legenditems) <- values$legenditemNames
    #   values$legenditems <- as.list(legenditems)
    # })


  observeEvent(values$NrOfTraces, { 
    values$dYNbs_cyl_el <- rep(T,values$NrOfTraces)
    names(values$dYNbs_cyl_el) <- sapply(1:values$NrOfTraces, function(x) {YNElement(x)})
  })

  output$YNbuttons <- renderUI({
    req(values$NrOfTraces)
    lapply(1:values$NrOfTraces, function(el) {
      YNb <- YNElement(el)
      if(values$dYNbs_cyl_el[[YNb]] == T ) {
        div(actionButton(inputId = YNb, label = icon("check"), style = "color: #339FFF;   background-color: white;  border-color: #339FFF;height: 34px; width: 34px; border-radius: 6px;  border-width: 2px; text-align: center;  line-height: 50%; padding: 0px; display:block; margin: 2px"))
      } else {
        div(actionButton(inputId = YNb, label = icon("times"), style = "color: #ff4d4d;   background-color: white;  border-color: #ff4d4d;height: 34px; width: 34px; border-radius: 6px;  border-width: 2px; text-align: center;  line-height: 50%; padding: 0px; display:block; margin: 2px"))
      }
    })
  })  

  flipYNb_FP1 <- function(idx){
    YNb <- YNElement(idx)
    values$dYNbs_cyl_el[[YNb]] <- !values$dYNbs_cyl_el[[YNb]]
  }

  observe({
    lapply(1:values$NrOfTraces, function(ob) {
      YNElement <- YNElement(ob)
      observeEvent(input[[YNElement]], {
        flipYNb_FP1(ob)
      }, ignoreInit = T)
    })
  })

  observeEvent(input$tracesPlot1, {
    listTraces <- input$tracesPlot1
    values$legenditems <- listTraces
    listTracesTF <- gsub('legendonly', FALSE, listTraces)
    listTracesTF <- as.logical(listTracesTF)
    lapply(1:values$NrOfTraces, function(el) {
      if(el <= length(listTracesTF)) {
        YNb <- YNElement(el)
        if(values$dYNbs_cyl_el[[YNb]] != listTracesTF[el]) {
          values$dYNbs_cyl_el[[YNb]] <- listTracesTF[el]
        }
      }
    })
  })

  output$tracesPlot1 <- renderPrint({ unlist(input$tracesPlot1)  })
  output$tracesPlot2 <- renderPrint({ unlist(values$legenditems)  })


}
shinyApp(ui, server)

getPatientById操作

componentDidMount()

2 个答案:

答案 0 :(得分:1)

似乎您正在将数据从redux复制到本地状态。可能需要或不需要。至于您的目标,为什么不直接呈现从Redux接收的数据(而不将它们复制到状态)?在这种情况下,您可以跳过componentDidMount中的axios调用。

如果您仍然希望Redux中的数据处于状态,则可以将其复制到构造函数或componentDidMount中的状态。但是,这仅使副本一次。然后,如果需要保持来自Redux的数据并保持状态同步,则需要在componentWillReceiveProps中确保这一点。

我相信您当前设置遇到的问题是componentWillReceiveProps并未被要求进行首次渲染,因此没有任何内容被复制到您的状态。

答案 1 :(得分:0)

在重新安装时,您不能传递Redux状态并将其用于控制​​逻辑吗?我假设它来自patients Redux状态,因为您正在componentWillReceiveProps生命周期方法中使用它,所以如果是这样,您就不能这样做:

// rest of code emitted for brevity
componentDidMount = () => {
    // assuming init state for patients.patient is null
    if (!this.patients.patient && this.props.match.params.patient_id) {
      this.props.getPatientById(this.props.match.params.patient_id);
    }
  };

这假设this.props.patients.patient的初始状态是来自减速器的null。如果this.props.patients为null,则将控制逻辑代码更改为!this.props.patients && this.props.match.params.patient_id

这里的控制逻辑是说“如果患者为空,并且我们有参数ID,则进行API GET调用”。如果您已经有患者,那么它就不会打扰。