reactiveVal et reactiveValues Shiny : l’état modifiable que vous pouvez écrire

Conservez l’état que votre code définit — un compteur, une liste qui s’accumule, le dernier enregistrement cliqué — et lisez-le et mettez-le à jour de façon réactive.

Programming
Shiny

reactive() est en lecture seule : il recalcule à partir des entrées et vous ne pouvez pas le définir. Quand vous avez besoin d’un état que VOUS contrôlez — un compteur, un total cumulé, un journal qui grandit — utilisez reactiveVal() pour une valeur ou reactiveValues() pour plusieurs. Apprenez à les créer, les lire et les écrire depuis des observateurs, le patron accumulateur, et lequel choisir.

Date de publication

28 juin 2026

Modifié

7 juillet 2026

AstucePoints clés
  • reactive() est en lecture seule ; reactiveVal()/reactiveValues() sont modifiables. Un reactive() se recalcule à partir de ses entrées — vous ne pouvez pas lui affecter de valeur. Quand vous avez besoin d’un état que vous définissez, il vous faut une valeur réactive.
  • reactiveVal() conserve une valeur. Créez-la avec v <- reactiveVal(0), lisez-la en l’appelant v(), écrivez-la en l’appelant avec la nouvelle valeur v(v() + 1).
  • reactiveValues() conserve plusieurs valeurs liées. Créez rv <- reactiveValues(count = 0, log = character()), puis lisez et écrivez avec $ : rv$count et rv$count <- rv$count + 1.
  • Vous les écrivez depuis des observateurs. L’état change en réponse à des événements, donc la mise à jour vit presque toujours à l’intérieur d’observeEvent(input$go, { … }) — pas dans un reactive() ni un render*().
  • Le patron accumulateur fait grandir l’état à chaque événement : lisez la valeur courante, ajoutez-y, réécrivez-la — un compteur, une liste, une ligne ajoutée à un data frame.

Introduction

Un curseur que vous lisez avec input$bins, une valeur que vous calculez avec reactive() — cela couvre la plupart d’une application. Mais certains états ne sont ni une entrée ni calculés à partir d’une entrée. Un compteur de clics. Une liste qui grandit chaque fois que l’utilisateur ajoute un élément. Un enregistrement du dernier bouton pressé. C’est un état dont votre code est propriétaire : vous le définissez, vous le changez, et l’application réagit quand il change.

La programmation réactive vous a donné le modèle — sources, points de sortie, et le graphe qui réexécute ce qui a changé — et les outils en lecture seule (reactive(), observeEvent(), eventReactive()). Cette leçon est la pièce manquante : l’état réactif modifiable que vous pouvez écrire, avec reactiveVal() et reactiveValues().

NoteCopiez n’importe quel bloc dans app.R et exécutez-le en local

Le code de cette page n’est pas exécuté ici — une application Shiny a besoin d’une session R active, elle ne peut donc pas tourner dans une page web statique. Copiez n’importe quel bloc dans un fichier app.R et exécutez-le en local avec shiny::runApp() (ou cliquez sur Run App dans RStudio). Chaque extrait se dépose dans la fonction server d’une application.

La lacune que laisse reactive()

Un reactive() est une valeur calculée à partir de ses entrées. Il se recalcule quand ces entrées changent, et c’est tout ce qu’il fait — il n’y a aucun moyen de lui affecter une nouvelle valeur depuis l’extérieur. C’est voulu par conception : un reactive est en lecture seule.

total <- reactive({ sum(input$values) })   # recomputed from input$values
total(42)                                   # ERROR — you can't set a reactive()

Cela fonctionne parfaitement quand la valeur est une fonction des entrées. Cela se brise dès l’instant où vous voulez un état qui change sur un événement, pas sur une entrée. Un compteur monte quand un bouton est cliqué. Un journal grandit quand l’utilisateur soumet une ligne. L’étape courante d’un assistant avance sur « Suivant ». Aucun de ceux-ci n’est calculé à partir d’une entrée — ce sont des valeurs que votre code construit au fil du temps, et vous devez les écrire.

Pour cela, Shiny vous donne deux variables réactives que vous pouvez à la fois lire et définir : reactiveVal() pour une seule valeur et reactiveValues() pour plusieurs.

reactiveVal() : une seule valeur modifiable

reactiveVal() crée une valeur réactive. L’astuce, c’est que l’objet qu’il renvoie est une fonction, et vous utilisez cette même fonction de deux façons :

  • Lisez la valeur courante en l’appelant sans argument : v().
  • Écrivez une nouvelle valeur en l’appelant avec la nouvelle valeur : v(new).

Créez un compteur qui s’incrémente à chaque clic :

server <- function(input, output, session) {

  count <- reactiveVal(0)                 # create, initial value 0

  observeEvent(input$click, {
    count(count() + 1)                    # write: read current with count(), set new
  })

  output$n <- renderText({
    paste("Clicked", count(), "times")    # read: call count()
  })
}

Lisez attentivement la ligne d’écriture : count() à droite lit la valeur courante ; envelopper le tout dans count(…) la définit. Ainsi count(count() + 1) signifie « définir le compteur à un de plus qu’il ne l’est maintenant ». Comme count est réactif, dès que vous l’écrivez, output$n — qui lit count() — se réexécute et la page se met à jour. Vous ne dites jamais à la sortie de s’actualiser ; l’écriture la déclenche, exactement comme le ferait une entrée qui change.

La valeur initiale que vous passez à reactiveVal() fixe le type et le point de départ. reactiveVal(0) pour un nombre, reactiveVal("") pour du texte, reactiveVal(character()) pour un vecteur de caractères qui grandit, reactiveVal(NULL) pour « rien pour l’instant ».

reactiveValues() : plusieurs valeurs liées

Quand vous avez plusieurs morceaux d’état qui vont ensemble — un compteur, un journal, un indicateur de statut — ne créez pas trois reactiveVal() séparés. Utilisez reactiveValues(), qui vous donne un seul objet de type liste dont chaque élément est réactif indépendamment. Vous lisez et écrivez ses éléments avec $, exactement comme une liste :

server <- function(input, output, session) {

  rv <- reactiveValues(count = 0, log = character())   # create several at once

  observeEvent(input$add, {
    rv$count <- rv$count + 1                            # write with $
    rv$log   <- c(rv$log, paste("event", rv$count))     # append to the log
  })

  output$summary <- renderText({
    paste(rv$count, "events:", paste(rv$log, collapse = ", "))   # read with $
  })
}

Pas de parenthèses ici — rv$count le lit, rv$count <- … l’écrit. Cet accès par $ est la différence majeure avec reactiveVal() : il se lit comme du R ordinaire, et chaque élément déclenche des mises à jour par lui- même. Une sortie qui ne lit que rv$count se réexécute quand le compteur change mais pas quand un rv$status sans rapport change — donc regrouper un état lié dans un seul reactiveValues() ne vous coûte rien en recalcul supplémentaire.

reactiveVal vs reactiveValues vs reactive() : lequel quand

Les trois sont réactifs, mais ils répondent à des questions différentes. La distinction est définissable vs calculé, puis une valeur vs plusieurs :

Outil Pouvez-vous l’écrire ? Conserve Lire / écrire À utiliser quand…
reactive() Non (recalculé) une valeur calculée lire x() uniquement la valeur est une fonction des entrées (filtre, transformation, résumé)
reactiveVal() Oui une valeur dont vous êtes propriétaire lire v(), écrire v(new) un seul morceau d’état que vous définissez — un compteur, un indicateur, un « dernier cliqué »
reactiveValues() Oui plusieurs valeurs dont vous êtes propriétaire lire rv$x, écrire rv$x <- new plusieurs morceaux d’état liés qui changent indépendamment

La décision est rapide : la valeur est-elle calculée à partir des entrées, ou est-ce moi qui la définis ? Calculée → reactive(). Définie → une valeur réactive. Ensuite : une ou plusieurs ? Une → reactiveVal() ; plusieurs liées → un seul reactiveValues(). Ne dispersez pas de nombreux reactiveVal() pour des données qui vont manifestement ensemble (le nom, le thème et l’heure de dernière connexion d’une session utilisateur) — c’est exactement à cela que sert reactiveValues().

Le patron accumulateur : faire grandir l’état à chaque événement

La raison la plus courante de recourir à une valeur réactive est de construire l’état au fil des événements plutôt que de le recalculer. Chaque accumulateur suit les mêmes trois étapes à l’intérieur d’un observateur : lire la valeur courante, la combiner avec le nouvel élément, la réécrire.

Ajoutez à une liste qui grandit chaque fois qu’un bouton est cliqué :

server <- function(input, output, session) {

  items <- reactiveVal(character())          # start empty

  observeEvent(input$add, {
    items(c(items(), input$new_item))        # read, append, write back
  })

  output$list <- renderText({
    paste(items(), collapse = "\n")
  })
}

La même forme fonctionne pour un data frame — ajoutez une ligne à chaque fois, en construisant une table cumulée :

server <- function(input, output, session) {

  log <- reactiveVal(data.frame(time = character(), action = character()))

  observeEvent(input$record, {
    new_row <- data.frame(time = as.character(Sys.time()), action = input$action)
    log(rbind(log(), new_row))               # read, rbind the new row, write back
  })

  output$table <- renderTable({ log() })
}

Il n’y a pas de modification sur place ici, et c’est délibéré : vous rbind() un nouveau data frame et le réaffectez avec log(…). C’est la réaffectation que Shiny remarque — c’est ainsi que l’écriture est enregistrée comme un changement et réexécute la table. Tenter de modifier la valeur stockée sans la réaffecter (section suivante) ne fait silencieusement rien.

Problèmes fréquents

Lire un reactiveVal sans () vous donne la fonction, pas la valeur. count est l’objet réactif — une fonction ; count() est sa valeur courante. Écrire paste("Count:", count) affiche quelque chose comme Count: function (value) … au lieu du nombre. Appelez-le toujours : paste("Count:", count()). (Avec reactiveValues(), ce piège disparaît — rv$count lit déjà la valeur.)

Écrire rv$x <- à l’intérieur d’un reactive() ne fait rien d’utile — mettez-le dans un observateur. Un reactive() sert à renvoyer une valeur, pas à faire des effets de bord, et il ne s’exécute que lorsque quelque chose l’appelle. Les changements d’état appartiennent à un observateur : utilisez observeEvent(input$go, { rv$x <- … }) (ou observe()), qui s’exécute quand son déclencheur se déclenche. Affecter une valeur réactive depuis l’intérieur d’un render*() ou d’un reactive() est le bug classique « mon état ne se met jamais à jour ».

Une boucle infinie quand une valeur dépend d’elle-même. Si un observe() lit une valeur réactive et l’écrit aussi, l’écriture redéclenche l’observateur, qui écrit à nouveau — indéfiniment (Shiny renverra généralement une erreur avec un avertissement de cycle de réactivité). Utilisez observeEvent() avec un déclencheur précis pour que le bloc se déclenche sur l’événement, pas sur la valeur qu’il change ; ou lisez la valeur courante avec isolate() à l’intérieur de l’observateur pour que la lire ne crée pas la dépendance.

Questions fréquentes

reactive() est en lecture seule : il calcule une valeur à partir de ses entrées et la recalcule quand elles changent — vous l’appelez avec x() mais vous ne pouvez pas lui affecter de valeur. reactiveVal() est modifiable : il conserve une valeur que vous définissez, lue avec v() et écrite avec v(new). Utilisez reactive() pour des valeurs dérivées des entrées, reactiveVal() pour un état que vous contrôlez comme un compteur ou un indicateur.

Utilisez un reactiveVal() et mettez-le à jour à l’intérieur d’un observateur. Créez total <- reactiveVal(0), puis dans observeEvent(input$add, { total(total() + input$amount) }) lisez le total courant, ajoutez le nouveau montant, et réécrivez-le. Toute sortie qui lit total() se met à jour automatiquement.

Utilisez reactiveValues() quand vous avez plusieurs morceaux d’état liés qui changent indépendamment — un compteur, un journal et un indicateur de statut pour un même flux de travail, par exemple. Il vous donne un objet que vous lisez et écrivez avec $ (rv$count, rv$status <- "done"), et chaque élément déclenche des mises à jour par lui-même. Pour une seule valeur, reactiveVal() est plus simple.

L’objet que reactiveVal() renvoie est une fonction. Lisez la valeur courante en l’appelant vide : v(). Écrivez une nouvelle valeur en l’appelant avec cette valeur : v(42). Pour incrémenter, lisez et écrivez en une seule ligne : v(v() + 1). Oublier les parenthèses sur une lecture (v au lieu de v()) est l’erreur la plus courante.

Deux causes habituelles. Vous lui affectez une valeur depuis l’intérieur d’un reactive() ou d’un render*() au lieu d’un observateur — déplacez l’écriture dans observeEvent() ou observe(). Ou vous modifiez l’objet stocké sur place sans le réaffecter ; Shiny ne remarque un changement que lorsque vous réaffectez (rv$df <- rbind(rv$df, new_row)), donc écrivez toujours la nouvelle valeur entière.

Testez vos connaissances

Ajoutez un bouton (actionButton("log_it", "Log click")) et une sortie à une application. Chaque fois que le bouton est cliqué, ajoutez l’heure courante à un vecteur de caractères qui grandit et affichez la liste complète, dans l’ordre du plus récent ou du plus ancien, à votre choix. Utilisez une valeur réactive pour l’état.

Vous avez besoin d’un état que vous écrivez à chaque clic, alors recourez à reactiveVal(character()) (commencez vide). Écrivez-y à l’intérieur d’observeEvent(input$log_it, { … }) en utilisant le patron accumulateur : lisez le vecteur courant avec clicks(), ajoutez as.character(Sys.time()), et réécrivez le résultat avec clicks(…). Lisez-le dans un renderText() avec clicks().

server <- function(input, output, session) {

  clicks <- reactiveVal(character())

  observeEvent(input$log_it, {
    clicks(c(clicks(), as.character(Sys.time())))   # read, append, write back
  })

  output$click_log <- renderText({
    paste(clicks(), collapse = "\n")
  })
}

clicks <- reactiveVal(character()) crée un vecteur vide et modifiable. À chaque clic, l’observateur lit le vecteur courant avec clicks(), ajoute l’horodatage, et réécrit le nouveau vecteur — le patron accumulateur. Comme output$click_log lit clicks(), il se réexécute et affiche la liste mise à jour à chaque clic.

Vous devez suivre un seul compteur qui monte quand un bouton est cliqué. Quel outil devrait le conserver, et comment l’incrémentez-vous ?

A. reactive({ input$go }) — le lire avec count(). B. reactiveVal(0) — incrémenter avec count(count() + 1). C. reactiveValues(count = 0) — incrémenter avec count(count() + 1). D. Une simple variable count <- 0 — incrémenter avec count <- count + 1.

B. Un compteur est un seul morceau d’état que vous écrivez, donc reactiveVal(0) convient, et vous l’incrémentez en lisant et écrivant en un seul appel : count(count() + 1). A est faux — reactive() est en lecture seule, vous ne pouvez pas le définir. C utilise le bon conteneur mais la mauvaise syntaxe : reactiveValues() se lit/écrit avec $ (rv$count <- rv$count + 1), pas en l’appelant. D est faux — une simple variable n’est pas réactive, donc aucune sortie ne se met à jour quand elle change.

Conclusion

reactive() vous donne des valeurs calculées à partir des entrées ; reactiveVal() et reactiveValues() vous donnent un état que vous définissez vous-même. Recourez à reactiveVal() pour une seule valeur modifiable — un compteur, un indicateur, un enregistrement du dernier cliqué — en le lisant avec v() et en l’écrivant avec v(new). Recourez à reactiveValues() quand plusieurs valeurs liées vont ensemble, en lisant et écrivant avec $. Écrivez-les depuis des observateurs, suivez le patron accumulateur lire-ajouter-écrire pour faire grandir l’état, et rappelez-vous les deux pièges : appelez un reactiveVal avec () pour le lire, et réaffectez toujours la valeur entière pour que Shiny voie le changement.

L’état sous contrôle, la pièce suivante consiste à y répondre proprement — les observateurs et les événements qui déterminent quand votre code s’exécute.

Leçons connexes

Cette page vous a-t-elle été utile ?

Recevez les nouvelles leçons R & Python par e-mail

Pratique, reproductible, sans spam. Désinscription à tout moment.

Double opt-in. Nous ne partageons jamais votre e-mail.

Partager cette pageXLinkedInRedditHN

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {reactiveVal et reactiveValues Shiny : l’état modifiable que
    vous pouvez écrire},
  date = {2026-06-28},
  url = {https://www.datanovia.com/learn/programming/shiny/server/reactive-values},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“reactiveVal et reactiveValues Shiny : l’état modifiable que vous pouvez écrire.” 2026. June 28. https://www.datanovia.com/learn/programming/shiny/server/reactive-values.