mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-30 01:08:43 -05:00
276 lines
19 KiB
HTML
276 lines
19 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<!-- saved from url=(0014)about:internet -->
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
|
|
<title>Guide to Coding in Shiny</title>
|
|
|
|
<base target="_blank"/>
|
|
|
|
<style type="text/css">
|
|
body, td {
|
|
font-family: sans-serif;
|
|
background-color: white;
|
|
font-size: 12px;
|
|
margin: 8px;
|
|
}
|
|
|
|
tt, code, pre {
|
|
font-family: 'DejaVu Sans Mono', 'Droid Sans Mono', 'Lucida Console', Consolas, Monaco, monospace;
|
|
}
|
|
|
|
h1 {
|
|
font-size:2.2em;
|
|
}
|
|
|
|
h2 {
|
|
font-size:1.8em;
|
|
}
|
|
|
|
h3 {
|
|
font-size:1.4em;
|
|
}
|
|
|
|
h4 {
|
|
font-size:1.0em;
|
|
}
|
|
|
|
h5 {
|
|
font-size:0.9em;
|
|
}
|
|
|
|
h6 {
|
|
font-size:0.8em;
|
|
}
|
|
|
|
a:visited {
|
|
color: rgb(50%, 0%, 50%);
|
|
}
|
|
|
|
pre {
|
|
margin-top: 0;
|
|
max-width: 95%;
|
|
border: 1px solid #ccc;
|
|
}
|
|
|
|
pre code {
|
|
display: block; padding: 0.5em;
|
|
}
|
|
|
|
code.r {
|
|
background-color: #F8F8F8;
|
|
}
|
|
|
|
table, td, th {
|
|
border: none;
|
|
}
|
|
|
|
blockquote {
|
|
color:#666666;
|
|
margin:0;
|
|
padding-left: 1em;
|
|
border-left: 0.5em #EEE solid;
|
|
}
|
|
|
|
hr {
|
|
height: 0px;
|
|
border-bottom: none;
|
|
border-top-width: thin;
|
|
border-top-style: dotted;
|
|
border-top-color: #999999;
|
|
}
|
|
|
|
@media print {
|
|
* {
|
|
background: transparent !important;
|
|
color: black !important;
|
|
filter:none !important;
|
|
-ms-filter: none !important;
|
|
}
|
|
|
|
body {
|
|
font-size:12pt;
|
|
max-width:100%;
|
|
}
|
|
|
|
a, a:visited {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
hr {
|
|
visibility: hidden;
|
|
page-break-before: always;
|
|
}
|
|
|
|
pre, blockquote {
|
|
padding-right: 1em;
|
|
page-break-inside: avoid;
|
|
}
|
|
|
|
tr, img {
|
|
page-break-inside: avoid;
|
|
}
|
|
|
|
img {
|
|
max-width: 100% !important;
|
|
}
|
|
|
|
@page :left {
|
|
margin: 15mm 20mm 15mm 10mm;
|
|
}
|
|
|
|
@page :right {
|
|
margin: 15mm 10mm 15mm 20mm;
|
|
}
|
|
|
|
p, h2, h3 {
|
|
orphans: 3; widows: 3;
|
|
}
|
|
|
|
h2, h3 {
|
|
page-break-after: avoid;
|
|
}
|
|
}
|
|
|
|
</style>
|
|
|
|
<!-- Styles for R syntax highlighter -->
|
|
<style type="text/css">
|
|
pre .operator,
|
|
pre .paren {
|
|
color: rgb(104, 118, 135)
|
|
}
|
|
|
|
pre .literal {
|
|
color: rgb(88, 72, 246)
|
|
}
|
|
|
|
pre .number {
|
|
color: rgb(0, 0, 205);
|
|
}
|
|
|
|
pre .comment {
|
|
color: rgb(76, 136, 107);
|
|
}
|
|
|
|
pre .keyword {
|
|
color: rgb(0, 0, 255);
|
|
}
|
|
|
|
pre .identifier {
|
|
color: rgb(0, 0, 0);
|
|
}
|
|
|
|
pre .string {
|
|
color: rgb(3, 106, 7);
|
|
}
|
|
</style>
|
|
|
|
<!-- R syntax highlighter -->
|
|
<script type="text/javascript">
|
|
var hljs=new function(){function m(p){return p.replace(/&/gm,"&").replace(/</gm,"<")}function f(r,q,p){return RegExp(q,"m"+(r.cI?"i":"")+(p?"g":""))}function b(r){for(var p=0;p<r.childNodes.length;p++){var q=r.childNodes[p];if(q.nodeName=="CODE"){return q}if(!(q.nodeType==3&&q.nodeValue.match(/\s+/))){break}}}function h(t,s){var p="";for(var r=0;r<t.childNodes.length;r++){if(t.childNodes[r].nodeType==3){var q=t.childNodes[r].nodeValue;if(s){q=q.replace(/\n/g,"")}p+=q}else{if(t.childNodes[r].nodeName=="BR"){p+="\n"}else{p+=h(t.childNodes[r])}}}if(/MSIE [678]/.test(navigator.userAgent)){p=p.replace(/\r/g,"\n")}return p}function a(s){var r=s.className.split(/\s+/);r=r.concat(s.parentNode.className.split(/\s+/));for(var q=0;q<r.length;q++){var p=r[q].replace(/^language-/,"");if(e[p]){return p}}}function c(q){var p=[];(function(s,t){for(var r=0;r<s.childNodes.length;r++){if(s.childNodes[r].nodeType==3){t+=s.childNodes[r].nodeValue.length}else{if(s.childNodes[r].nodeName=="BR"){t+=1}else{if(s.childNodes[r].nodeType==1){p.push({event:"start",offset:t,node:s.childNodes[r]});t=arguments.callee(s.childNodes[r],t);p.push({event:"stop",offset:t,node:s.childNodes[r]})}}}}return t})(q,0);return p}function k(y,w,x){var q=0;var z="";var s=[];function u(){if(y.length&&w.length){if(y[0].offset!=w[0].offset){return(y[0].offset<w[0].offset)?y:w}else{return w[0].event=="start"?y:w}}else{return y.length?y:w}}function t(D){var A="<"+D.nodeName.toLowerCase();for(var B=0;B<D.attributes.length;B++){var C=D.attributes[B];A+=" "+C.nodeName.toLowerCase();if(C.value!==undefined&&C.value!==false&&C.value!==null){A+='="'+m(C.value)+'"'}}return A+">"}while(y.length||w.length){var v=u().splice(0,1)[0];z+=m(x.substr(q,v.offset-q));q=v.offset;if(v.event=="start"){z+=t(v.node);s.push(v.node)}else{if(v.event=="stop"){var p,r=s.length;do{r--;p=s[r];z+=("</"+p.nodeName.toLowerCase()+">")}while(p!=v.node);s.splice(r,1);while(r<s.length){z+=t(s[r]);r++}}}}return z+m(x.substr(q))}function j(){function q(x,y,v){if(x.compiled){return}var u;var s=[];if(x.k){x.lR=f(y,x.l||hljs.IR,true);for(var w in x.k){if(!x.k.hasOwnProperty(w)){continue}if(x.k[w] instanceof Object){u=x.k[w]}else{u=x.k;w="keyword"}for(var r in u){if(!u.hasOwnProperty(r)){continue}x.k[r]=[w,u[r]];s.push(r)}}}if(!v){if(x.bWK){x.b="\\b("+s.join("|")+")\\s"}x.bR=f(y,x.b?x.b:"\\B|\\b");if(!x.e&&!x.eW){x.e="\\B|\\b"}if(x.e){x.eR=f(y,x.e)}}if(x.i){x.iR=f(y,x.i)}if(x.r===undefined){x.r=1}if(!x.c){x.c=[]}x.compiled=true;for(var t=0;t<x.c.length;t++){if(x.c[t]=="self"){x.c[t]=x}q(x.c[t],y,false)}if(x.starts){q(x.starts,y,false)}}for(var p in e){if(!e.hasOwnProperty(p)){continue}q(e[p].dM,e[p],true)}}function d(B,C){if(!j.called){j();j.called=true}function q(r,M){for(var L=0;L<M.c.length;L++){if((M.c[L].bR.exec(r)||[null])[0]==r){return M.c[L]}}}function v(L,r){if(D[L].e&&D[L].eR.test(r)){return 1}if(D[L].eW){var M=v(L-1,r);return M?M+1:0}return 0}function w(r,L){return L.i&&L.iR.test(r)}function K(N,O){var M=[];for(var L=0;L<N.c.length;L++){M.push(N.c[L].b)}var r=D.length-1;do{if(D[r].e){M.push(D[r].e)}r--}while(D[r+1].eW);if(N.i){M.push(N.i)}return f(O,M.join("|"),true)}function p(M,L){var N=D[D.length-1];if(!N.t){N.t=K(N,E)}N.t.lastIndex=L;var r=N.t.exec(M);return r?[M.substr(L,r.index-L),r[0],false]:[M.substr(L),"",true]}function z(N,r){var L=E.cI?r[0].toLowerCase():r[0];var M=N.k[L];if(M&&M instanceof Array){return M}return false}function F(L,P){L=m(L);if(!P.k){return L}var r="";var O=0;P.lR.lastIndex=0;var M=P.lR.exec(L);while(M){r+=L.substr(O,M.index-O);var N=z(P,M);if(N){x+=N[1];r+='<span class="'+N[0]+'">'+M[0]+"</span>"}else{r+=M[0]}O=P.lR.lastIndex;M=P.lR.exec(L)}return r+L.substr(O,L.length-O)}function J(L,M){if(M.sL&&e[M.sL]){var r=d(M.sL,L);x+=r.keyword_count;return r.value}else{return F(L,M)}}function I(M,r){var L=M.cN?'<span class="'+M.cN+'">':"";if(M.rB){y+=L;M.buffer=""}else{if(M.eB){y+=m(r)+L;M.buffer=""}else{y+=L;M.buffer=r}}D.push(M);A+=M.r}function G(N,M,Q){var R=D[D.length-1];if(Q){y+=J(R.buffer+N,R);return false}var P=q(M,R);if(P){y+=J(R.buffer+N,R);I(P,M);return P.rB}var L=v(D.length-1,M);if(L){var O=R.cN?"</span>":"";if(R.rE){y+=J(R.buffer+N,R)+O}else{if(R.eE){y+=J(R.buffer+N,R)+O+m(M)}else{y+=J(R.buffer+N+M,R)+O}}while(L>1){O=D[D.length-2].cN?"</span>":"";y+=O;L--;D.length--}var r=D[D.length-1];D.length--;D[D.length-1].buffer="";if(r.starts){I(r.starts,"")}return R.rE}if(w(M,R)){throw"Illegal"}}var E=e[B];var D=[E.dM];var A=0;var x=0;var y="";try{var s,u=0;E.dM.buffer="";do{s=p(C,u);var t=G(s[0],s[1],s[2]);u+=s[0].length;if(!t){u+=s[1].length}}while(!s[2]);if(D.length>1){throw"Illegal"}return{r:A,keyword_count:x,value:y}}catch(H){if(H=="Illegal"){return{r:0,keyword_count:0,value:m(C)}}else{throw H}}}function g(t){var p={keyword_count:0,r:0,value:m(t)};var r=p;for(var q in e){if(!e.hasOwnProperty(q)){continue}var s=d(q,t);s.language=q;if(s.keyword_count+s.r>r.keyword_count+r.r){r=s}if(s.keyword_count+s.r>p.keyword_count+p.r){r=p;p=s}}if(r.language){p.second_best=r}return p}function i(r,q,p){if(q){r=r.replace(/^((<[^>]+>|\t)+)/gm,function(t,w,v,u){return w.replace(/\t/g,q)})}if(p){r=r.replace(/\n/g,"<br>")}return r}function n(t,w,r){var x=h(t,r);var v=a(t);var y,s;if(v){y=d(v,x)}else{return}var q=c(t);if(q.length){s=document.createElement("pre");s.innerHTML=y.value;y.value=k(q,c(s),x)}y.value=i(y.value,w,r);var u=t.className;if(!u.match("(\\s|^)(language-)?"+v+"(\\s|$)")){u=u?(u+" "+v):v}if(/MSIE [678]/.test(navigator.userAgent)&&t.tagName=="CODE"&&t.parentNode.tagName=="PRE"){s=t.parentNode;var p=document.createElement("div");p.innerHTML="<pre><code>"+y.value+"</code></pre>";t=p.firstChild.firstChild;p.firstChild.cN=s.cN;s.parentNode.replaceChild(p.firstChild,s)}else{t.innerHTML=y.value}t.className=u;t.result={language:v,kw:y.keyword_count,re:y.r};if(y.second_best){t.second_best={language:y.second_best.language,kw:y.second_best.keyword_count,re:y.second_best.r}}}function o(){if(o.called){return}o.called=true;var r=document.getElementsByTagName("pre");for(var p=0;p<r.length;p++){var q=b(r[p]);if(q){n(q,hljs.tabReplace)}}}function l(){if(window.addEventListener){window.addEventListener("DOMContentLoaded",o,false);window.addEventListener("load",o,false)}else{if(window.attachEvent){window.attachEvent("onload",o)}else{window.onload=o}}}var e={};this.LANGUAGES=e;this.highlight=d;this.highlightAuto=g;this.fixMarkup=i;this.highlightBlock=n;this.initHighlighting=o;this.initHighlightingOnLoad=l;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="\\b(0[xX][a-fA-F0-9]+|(\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.ER="(?![\\s\\S])";this.BE={b:"\\\\.",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.inherit=function(r,s){var p={};for(var q in r){p[q]=r[q]}if(s){for(var q in s){p[q]=s[q]}}return p}}();hljs.LANGUAGES.cpp=function(){var a={keyword:{"false":1,"int":1,"float":1,"while":1,"private":1,"char":1,"catch":1,"export":1,virtual:1,operator:2,sizeof:2,dynamic_cast:2,typedef:2,const_cast:2,"const":1,struct:1,"for":1,static_cast:2,union:1,namespace:1,unsigned:1,"long":1,"throw":1,"volatile":2,"static":1,"protected":1,bool:1,template:1,mutable:1,"if":1,"public":1,friend:2,"do":1,"return":1,"goto":1,auto:1,"void":2,"enum":1,"else":1,"break":1,"new":1,extern:1,using:1,"true":1,"class":1,asm:1,"case":1,typeid:1,"short":1,reinterpret_cast:2,"default":1,"double":1,register:1,explicit:1,signed:1,typename:1,"try":1,"this":1,"switch":1,"continue":1,wchar_t:1,inline:1,"delete":1,alignof:1,char16_t:1,char32_t:1,constexpr:1,decltype:1,noexcept:1,nullptr:1,static_assert:1,thread_local:1,restrict:1,_Bool:1,complex:1},built_in:{std:1,string:1,cin:1,cout:1,cerr:1,clog:1,stringstream:1,istringstream:1,ostringstream:1,auto_ptr:1,deque:1,list:1,queue:1,stack:1,vector:1,map:1,set:1,bitset:1,multiset:1,multimap:1,unordered_set:1,unordered_map:1,unordered_multiset:1,unordered_multimap:1,array:1,shared_ptr:1}};return{dM:{k:a,i:"</",c:[hljs.CLCM,hljs.CBLCLM,hljs.QSM,{cN:"string",b:"'\\\\?.",e:"'",i:"."},{cN:"number",b:"\\b(\\d+(\\.\\d*)?|\\.\\d+)(u|U|l|L|ul|UL|f|F)"},hljs.CNM,{cN:"preprocessor",b:"#",e:"$"},{cN:"stl_container",b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:a,r:10,c:["self"]}]}}}();hljs.LANGUAGES.r={dM:{c:[hljs.HCM,{cN:"number",b:"\\b0[xX][0-9a-fA-F]+[Li]?\\b",e:hljs.IMMEDIATE_RE,r:0},{cN:"number",b:"\\b\\d+(?:[eE][+\\-]?\\d*)?L\\b",e:hljs.IMMEDIATE_RE,r:0},{cN:"number",b:"\\b\\d+\\.(?!\\d)(?:i\\b)?",e:hljs.IMMEDIATE_RE,r:1},{cN:"number",b:"\\b\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",e:hljs.IMMEDIATE_RE,r:0},{cN:"number",b:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",e:hljs.IMMEDIATE_RE,r:1},{cN:"keyword",b:"(?:tryCatch|library|setGeneric|setGroupGeneric)\\b",e:hljs.IMMEDIATE_RE,r:10},{cN:"keyword",b:"\\.\\.\\.",e:hljs.IMMEDIATE_RE,r:10},{cN:"keyword",b:"\\.\\.\\d+(?![\\w.])",e:hljs.IMMEDIATE_RE,r:10},{cN:"keyword",b:"\\b(?:function)",e:hljs.IMMEDIATE_RE,r:2},{cN:"keyword",b:"(?:if|in|break|next|repeat|else|for|return|switch|while|try|stop|warning|require|attach|detach|source|setMethod|setClass)\\b",e:hljs.IMMEDIATE_RE,r:1},{cN:"literal",b:"(?:NA|NA_integer_|NA_real_|NA_character_|NA_complex_)\\b",e:hljs.IMMEDIATE_RE,r:10},{cN:"literal",b:"(?:NULL|TRUE|FALSE|T|F|Inf|NaN)\\b",e:hljs.IMMEDIATE_RE,r:1},{cN:"identifier",b:"[a-zA-Z.][a-zA-Z0-9._]*\\b",e:hljs.IMMEDIATE_RE,r:0},{cN:"operator",b:"<\\-(?!\\s*\\d)",e:hljs.IMMEDIATE_RE,r:2},{cN:"operator",b:"\\->|<\\-",e:hljs.IMMEDIATE_RE,r:1},{cN:"operator",b:"%%|~",e:hljs.IMMEDIATE_RE},{cN:"operator",b:">=|<=|==|!=|\\|\\||&&|=|\\+|\\-|\\*|/|\\^|>|<|!|&|\\||\\$|:",e:hljs.IMMEDIATE_RE,r:0},{cN:"operator",b:"%",e:"%",i:"\\n",r:1},{cN:"identifier",b:"`",e:"`",r:0},{cN:"string",b:'"',e:'"',c:[hljs.BE],r:0},{cN:"string",b:"'",e:"'",c:[hljs.BE],r:0},{cN:"paren",b:"[[({\\])}]",e:hljs.IMMEDIATE_RE,r:0}]}};
|
|
hljs.initHighlightingOnLoad();
|
|
</script>
|
|
|
|
|
|
|
|
|
|
</head>
|
|
|
|
<body>
|
|
<style type="text/css">
|
|
p {font-size: 140%}
|
|
</style>
|
|
|
|
<h1>Guide to Coding in Shiny</h1>
|
|
|
|
<p>The Shiny web framework is fundamentally about making it easy to wire up <em>input values</em> from a web page, making them easily available to you in R, and have the results of your R code be written as <em>output values</em> back out to the web page.</p>
|
|
|
|
<pre><code>input values => R code => output values
|
|
</code></pre>
|
|
|
|
<p>Since Shiny web apps are interactive, the input values can change at any time, and the output values need to be updated immediately to reflect those changes.</p>
|
|
|
|
<p>Shiny comes with a <strong>reactive programming</strong> library that you will use to structure your application logic. By using this library, changing input values will naturally cause the right parts of your R code to be reexecuted, which will in turn cause any changed outputs to be updated.</p>
|
|
|
|
<h2>Reactive Programming: The Basics</h2>
|
|
|
|
<p>Reactive programming is a coding style that starts with <strong>reactive values</strong>–values that change over time, or in response to the user–and builds on top of them with <strong>reactive functions</strong>–functions that access reactive values and execute other reactive functions.</p>
|
|
|
|
<p>What's interesting about reactive functions is that whenever they execute, they automatically keep track of what reactive values they read and what reactive functions they called. If those “dependencies” become out of date, then they know that their own return value has also become out of date. Because of this dependency tracking, changing a reactive value will automatically instruct all reactive functions that directly or indirectly depended on that value to re-execute.</p>
|
|
|
|
<p>The most common way you'll encounter reactive values in Shiny is using the <code>input</code> object. The <code>input</code> object, which is automatically in scope when your Shiny application's R code runs, lets you access the web page's user input fields using a list-like syntax. For example, if there was a text field named <code>foo</code> in your HTML, you would access it in your R code with <code>input$foo</code>. Code-wise, it looks like you're grabbing a value from a list or data frame, but you're actually reading a reactive value.</p>
|
|
|
|
<p>That brings us to the first constraint of the reactive framework: <strong>reactive values can only be read from inside a reactive function.</strong> It doesn't need to be the currently executing function that's reactive; it can be the function that's calling the current function, or the function that's calling that one, and so on. But if none of the functions on the current call stack are reactive, then attempting to read a reactive value will give you an error telling you so.</p>
|
|
|
|
<p>To create a reactive function, just take a regular function, and wrap it in a call to <code>reactive</code>:</p>
|
|
|
|
<pre><code class="r">reactive(function() {
|
|
print(input$foo)
|
|
})
|
|
</code></pre>
|
|
|
|
<p>This creates a reactive function that depends on <code>input$foo</code>. Whenever the value of <code>input$foo</code> changes, the function will execute and print the value.</p>
|
|
|
|
<pre><code class="r">a.to.b <- reactive(function() {
|
|
input$a:input$b
|
|
})
|
|
</code></pre>
|
|
|
|
<p>To explain how reactive programming works, let's step through a series of examples.</p>
|
|
|
|
<h2>Example 1: Hello World</h2>
|
|
|
|
<p>Our simplest example app will present the user with a textbox; anything that is typed into the textbox will be echoed back to the user in uppercase.</p>
|
|
|
|
<p>index.html (abridged):</p>
|
|
|
|
<pre><code class="html"><p>
|
|
Input:<br/>
|
|
<input name="val" type="text" value="Hello World!"/>
|
|
</p>
|
|
|
|
<p>
|
|
You said:<br/>
|
|
<div id="valUpper" class="shiny-text-output"/>
|
|
</p>
|
|
</code></pre>
|
|
|
|
<p>app.R:</p>
|
|
|
|
<pre><code class="r">output$valUpper <- reactive(function() {
|
|
toupper(input$val)
|
|
})
|
|
</code></pre>
|
|
|
|
<p>Lauch Example App 1 and try it out. [TODO: Directions for how to launch example app 1] You can see that as you type into the textbox, the output immediately updates.</p>
|
|
|
|
<p>Take a look at app.R. You probably figured out that <code>input$val</code> is how we access the value of the <code>val</code> field in index.html, and assigning to <code>output$echo</code> is how we define what goes into the <code>valUpper</code> div.</p>
|
|
|
|
<p>The only thing that needs explanation here is <code>reactive</code>. You pass it a function, and it returns to you a <strong>reactive</strong> version of that same function.</p>
|
|
|
|
<p>Now it's time to explain what <em>reactive</em> actually means.</p>
|
|
|
|
<ul>
|
|
<li>A <strong>reactive value</strong> is a value that may change in the future.</li>
|
|
<li>A <strong>reactive function</strong> is a function that accesses reactive values and/or executes other reactive functions. (It can also access regular, non-reactive values and execute regular, non-reactive functions; otherwise, it'd be hard to get them to do anything useful!)</li>
|
|
</ul>
|
|
|
|
<p>The unique thing about reactive values and functions is that they track their own dependencies. That is, when you execute a reactive function, it's actually doing two things:</p>
|
|
|
|
<ol>
|
|
<li>Evaluating the function body and returning a value (just like any other R function)</li>
|
|
<li>Keeping track of what other reactive functions are being called and what reactive values are being accessed</li>
|
|
</ol>
|
|
|
|
<p>When a reactive value changes, any reactive functions that previously accessed this value (and thus “depended” on it) are notified that they are out of date and need to re-execute. Those reactive functions, in turn, will notify any reactive functions that depended on them, and so on.</p>
|
|
|
|
<p>In this case, our function calls <code>input$val</code>, so that counts as one of the inputs. Whenever the user makes a change to <code>val</code>, this function notices the change and re-executes itself. And since the <code>output</code> data structure is designed to work with reactive functions, it'll notice when the re-execution happens and send the result back to the web page.</p>
|
|
|
|
</body>
|
|
|
|
</html>
|
|
|