Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shiny and vuex #7

Open
timelyportfolio opened this issue Aug 9, 2020 · 0 comments
Open

Shiny and vuex #7

timelyportfolio opened this issue Aug 9, 2020 · 0 comments

Comments

@timelyportfolio
Copy link
Collaborator

timelyportfolio commented Aug 9, 2020

I often wonder why does Shiny manage UI state from R instead of UI state (especially state that does not affect/require R) being managed in JavaScript. If we pursue this approach with vuex then JavaScript would manage all UI/frontend state and call R only when necessary allowing JS/HTML/CSS to do what it does best and more directly. This decision does not require vuex, but in a vue context I think vuex is a good established solution.

Code

# quick example of Vuex and Shiny
# reference: https://vuex.vuejs.org/guide/

library(htmltools)
library(shiny)
library(vueR)

vuex <- tags$script(src="https://unpkg.com/[email protected]/dist/vuex.js")

ui <- tagList(
  html_dependency_vue(offline = FALSE, minified = FALSE),
  tags$head(vuex),
  tags$h1("Shiny with Vue and Vuex"),
  tags$h3('Vue App'),
  tags$div(
    id = "app",
    tags$button(`@click`="increment", "+"),
    tags$button(`@click`="decrement", "-"),
    "{{ count }}"
  ),
  tags$h3("Shiny controls"),
  # add Shiny buttons to demonstrate Shiny to update Vuex state
  actionButton(inputId = "btnIncrement", label="+"),
  actionButton(inputId = "btnDecrement", label="-"),
  tags$script(HTML(
"
// first example in Vuex documentation
Vue.use(Vuex)

// make sure to call Vue.use(Vuex) if using a module system

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment: state => state.count++,
    decrement: state => state.count--
  }
})

const app = new Vue({
  el: '#app',
  store: store,
  computed: {
    count () {
      return this.$store.state.count
    }
  },
  methods: {
    increment () {
      this.$store.commit('increment')
    },
    decrement () {
    	this.$store.commit('decrement')
    }
  }
})

$(document).on('shiny:sessioninitialized', function() {
  // increment from Shiny custom message
  //   chose 'increment' but does not have to match the store mutation name
  Shiny.addCustomMessageHandler('increment', function(msg) {
    app.$store.commit('increment')
  });
  Shiny.addCustomMessageHandler('decrement', function(msg) {
    app.$store.commit('decrement')
  });
})
"
  ))
)

#browsable(ui)

server <- function(input, output, session) {
  observeEvent(input$btnIncrement, {
    session$sendCustomMessage("increment", list())
  })
  observeEvent(input$btnDecrement, {
    session$sendCustomMessage("decrement", list())
  })
}

shinyApp(
  ui = ui,
  server = server,
  options = list(launch.browser = rstudioapi::viewer)
)

vuer_7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant