[{"data":1,"prerenderedAt":1568},["ShallowReactive",2],{"content-/vue-reactivity-props-binding":3,"all-pages-for-dir":1546,"related-/vue-reactivity-props-binding":1547,"og-image-/vue-reactivity-props-binding":1567},{"id":4,"title":5,"body":6,"category":1533,"concepts":1533,"description":1534,"extension":1535,"meta":1536,"navigation":277,"ogImage":1533,"path":1537,"project_name":1533,"published":1538,"publishedAt":1539,"seo":1540,"source":1533,"stem":1541,"tags":1542,"todo":1533,"unpublished":1538,"updatedAt":1539,"__hash__":1545},"pages/2025-12/2025-12-10/vue-reactivity-props-binding.md","Vue 3のリアクティビティとpropsバインディングの仕組み",{"type":7,"value":8,"toc":1517},"minimark",[9,13,17,21,32,36,81,90,94,151,157,213,216,433,437,484,490,493,569,572,633,636,641,667,670,673,687,690,693,696,1195,1199,1443,1446,1506,1513],[10,11,5],"h1",{"id":12},"vue-3のリアクティビティとpropsバインディングの仕組み",[14,15,16],"p",{},"Vueのリアクティビティシステムによるデータ連携の仕組みを、財務チャートのアニメーション実装で使用している例をもとに解説します。",[18,19,20],"h2",{"id":20},"全体の構成",[22,23,28],"pre",{"className":24,"code":26,"language":27},[25],"language-text","┌─────────────────────────────────────────────────────────┐\n│  親コンポーネント (proportional-animation.vue)            │\n│                                                         │\n│  const microsoftPeriodIndex = ref(0)  ← リアクティブな状態 │\n│                                                         │\n│  ┌─────────────────────────────────────────────────┐   │\n│  │ ProportionalFinancialStatementsAnimated         │   │\n│  │   v-model=\"microsoftPeriodIndex\"                │   │\n│  │   （双方向バインディング - 値を読み書き）          │   │\n│  └─────────────────────────────────────────────────┘   │\n│                                                         │\n│  ┌─────────────────────────────────────────────────┐   │\n│  │ AnimationControlPanel                           │   │\n│  │   v-model=\"microsoftPeriodIndex\"                │   │\n│  │   （双方向バインディング - 値を読み書き）          │   │\n│  └─────────────────────────────────────────────────┘   │\n│                                                         │\n│  ┌─────────────────────────────────────────────────┐   │\n│  │ EPSChart / FCFChart / ProfitMarginChart など     │   │\n│  │   :current-period-index=\"microsoftPeriodIndex\"  │   │\n│  │   （読み取り専用 - 値を受け取るだけ）             │   │\n│  └─────────────────────────────────────────────────┘   │\n└─────────────────────────────────────────────────────────┘\n","text",[29,30,26],"code",{"__ignoreMap":31},"",[18,33,35],{"id":34},"step-1-リアクティブな状態の定義","Step 1: リアクティブな状態の定義",[22,37,41],{"className":38,"code":39,"language":40,"meta":31,"style":31},"language-typescript shiki shiki-themes vitesse-light vitesse-light","// 親コンポーネントで ref を使って状態を定義\nconst microsoftPeriodIndex = ref(0)\n","typescript",[29,42,43,52],{"__ignoreMap":31},[44,45,48],"span",{"class":46,"line":47},"line",1,[44,49,51],{"class":50},"sxvE3","// 親コンポーネントで ref を使って状態を定義\n",[44,53,55,59,63,67,71,74,78],{"class":46,"line":54},2,[44,56,58],{"class":57},"stQ0i","const ",[44,60,62],{"class":61},"s4oTP","microsoftPeriodIndex",[44,64,66],{"class":65},"shFtX"," =",[44,68,70],{"class":69},"senZ8"," ref",[44,72,73],{"class":65},"(",[44,75,77],{"class":76},"sM54T","0",[44,79,80],{"class":65},")\n",[14,82,83,86,87,89],{},[29,84,85],{},"ref(0)"," は初期値 ",[29,88,77],{}," を持つリアクティブな参照を作成します。この値が変更されると、この値を参照しているすべての場所が自動的に再レンダリングされます。",[18,91,93],{"id":92},"step-2-v-model-による双方向バインディング","Step 2: v-model による双方向バインディング",[22,95,99],{"className":96,"code":97,"language":98,"meta":31,"style":31},"language-vue shiki shiki-themes vitesse-light vitesse-light","\u003CAnimationControlPanel\n  v-model=\"microsoftPeriodIndex\"\n  :labels=\"microsoftPeriodLabels\"\n/>\n","vue",[29,100,101,110,126,144],{"__ignoreMap":31},[44,102,103,106],{"class":46,"line":47},[44,104,105],{"class":65},"\u003C",[44,107,109],{"class":108},"sHkkW","AnimationControlPanel\n",[44,111,112,115,118,121,123],{"class":46,"line":54},[44,113,114],{"class":69},"  v-model",[44,116,117],{"class":65},"=",[44,119,120],{"class":65},"\"",[44,122,62],{"class":61},[44,124,125],{"class":65},"\"\n",[44,127,129,132,135,137,139,142],{"class":46,"line":128},3,[44,130,131],{"class":65},"  :",[44,133,134],{"class":69},"labels",[44,136,117],{"class":65},[44,138,120],{"class":65},[44,140,141],{"class":61},"microsoftPeriodLabels",[44,143,125],{"class":65},[44,145,147],{"class":46,"line":146},4,[44,148,150],{"class":149},"sG7-3","/>\n",[14,152,153,156],{},[29,154,155],{},"v-model"," は以下のショートハンドです：",[22,158,160],{"className":96,"code":159,"language":98,"meta":31,"style":31},"\u003CAnimationControlPanel\n  :modelValue=\"microsoftPeriodIndex\"\n  @update:modelValue=\"microsoftPeriodIndex = $event\"\n/>\n",[29,161,162,168,183,209],{"__ignoreMap":31},[44,163,164,166],{"class":46,"line":47},[44,165,105],{"class":65},[44,167,109],{"class":108},[44,169,170,172,175,177,179,181],{"class":46,"line":54},[44,171,131],{"class":65},[44,173,174],{"class":69},"modelValue",[44,176,117],{"class":65},[44,178,120],{"class":65},[44,180,62],{"class":61},[44,182,125],{"class":65},[44,184,185,188,191,194,196,198,200,202,204,207],{"class":46,"line":128},[44,186,187],{"class":65},"  @",[44,189,190],{"class":69},"update",[44,192,193],{"class":65},":",[44,195,174],{"class":69},[44,197,117],{"class":65},[44,199,120],{"class":65},[44,201,62],{"class":61},[44,203,66],{"class":65},[44,205,206],{"class":61}," $event",[44,208,125],{"class":65},[44,210,211],{"class":46,"line":146},[44,212,150],{"class":149},[14,214,215],{},"子コンポーネント側での実装：",[22,217,219],{"className":38,"code":218,"language":40,"meta":31,"style":31},"// AnimationControlPanel.vue\nconst props = defineProps\u003C{\n  modelValue: number\n  labels: string[]\n}>()\n\nconst emit = defineEmits\u003C{\n  'update:modelValue': [value: number]\n}>()\n\n// 値を変更する時\nconst goToNext = () => {\n  const nextIndex = (props.modelValue + 1) % props.labels.length\n  emit('update:modelValue', nextIndex)  // 親に通知\n}\n",[29,220,221,226,241,253,266,272,279,294,322,327,332,338,357,402,427],{"__ignoreMap":31},[44,222,223],{"class":46,"line":47},[44,224,225],{"class":50},"// AnimationControlPanel.vue\n",[44,227,228,230,233,235,238],{"class":46,"line":54},[44,229,58],{"class":57},[44,231,232],{"class":61},"props",[44,234,66],{"class":65},[44,236,237],{"class":69}," defineProps",[44,239,240],{"class":65},"\u003C{\n",[44,242,243,246,249],{"class":46,"line":128},[44,244,245],{"class":61},"  modelValue",[44,247,248],{"class":65},": ",[44,250,252],{"class":251},"sSkh3","number\n",[44,254,255,258,260,263],{"class":46,"line":146},[44,256,257],{"class":61},"  labels",[44,259,248],{"class":65},[44,261,262],{"class":251},"string",[44,264,265],{"class":65},"[]\n",[44,267,269],{"class":46,"line":268},5,[44,270,271],{"class":65},"}>()\n",[44,273,275],{"class":46,"line":274},6,[44,276,278],{"emptyLinePlaceholder":277},true,"\n",[44,280,282,284,287,289,292],{"class":46,"line":281},7,[44,283,58],{"class":57},[44,285,286],{"class":61},"emit",[44,288,66],{"class":65},[44,290,291],{"class":69}," defineEmits",[44,293,240],{"class":65},[44,295,297,301,305,308,311,314,316,319],{"class":46,"line":296},8,[44,298,300],{"class":299},"sMJiu","  '",[44,302,304],{"class":303},"sdGka","update:modelValue",[44,306,307],{"class":299},"'",[44,309,310],{"class":65},": [",[44,312,313],{"class":69},"value",[44,315,248],{"class":65},[44,317,318],{"class":251},"number",[44,320,321],{"class":65},"]\n",[44,323,325],{"class":46,"line":324},9,[44,326,271],{"class":65},[44,328,330],{"class":46,"line":329},10,[44,331,278],{"emptyLinePlaceholder":277},[44,333,335],{"class":46,"line":334},11,[44,336,337],{"class":50},"// 値を変更する時\n",[44,339,341,343,346,348,351,354],{"class":46,"line":340},12,[44,342,58],{"class":57},[44,344,345],{"class":69},"goToNext",[44,347,66],{"class":65},[44,349,350],{"class":65}," ()",[44,352,353],{"class":65}," =>",[44,355,356],{"class":65}," {\n",[44,358,360,363,366,368,371,373,376,378,381,384,387,390,392,394,396,398],{"class":46,"line":359},13,[44,361,362],{"class":57},"  const ",[44,364,365],{"class":61},"nextIndex",[44,367,66],{"class":65},[44,369,370],{"class":65}," (",[44,372,232],{"class":61},[44,374,375],{"class":65},".",[44,377,174],{"class":61},[44,379,380],{"class":57}," + ",[44,382,383],{"class":76},"1",[44,385,386],{"class":65},")",[44,388,389],{"class":57}," % ",[44,391,232],{"class":61},[44,393,375],{"class":65},[44,395,134],{"class":61},[44,397,375],{"class":65},[44,399,401],{"class":400},"sz8Xr","length\n",[44,403,405,408,410,412,414,416,419,422,424],{"class":46,"line":404},14,[44,406,407],{"class":69},"  emit",[44,409,73],{"class":65},[44,411,307],{"class":299},[44,413,304],{"class":303},[44,415,307],{"class":299},[44,417,418],{"class":65},",",[44,420,421],{"class":61}," nextIndex",[44,423,386],{"class":65},[44,425,426],{"class":50},"  // 親に通知\n",[44,428,430],{"class":46,"line":429},15,[44,431,432],{"class":65},"}\n",[18,434,436],{"id":435},"step-3-props-による読み取り専用バインディング","Step 3: props による読み取り専用バインディング",[22,438,440],{"className":96,"code":439,"language":98,"meta":31,"style":31},"\u003CEPSChart\n  :eps-data=\"microsoftEpsData\"\n  :current-period-index=\"microsoftPeriodIndex\"\n/>\n",[29,441,442,449,465,480],{"__ignoreMap":31},[44,443,444,446],{"class":46,"line":47},[44,445,105],{"class":65},[44,447,448],{"class":108},"EPSChart\n",[44,450,451,453,456,458,460,463],{"class":46,"line":54},[44,452,131],{"class":65},[44,454,455],{"class":69},"eps-data",[44,457,117],{"class":65},[44,459,120],{"class":65},[44,461,462],{"class":61},"microsoftEpsData",[44,464,125],{"class":65},[44,466,467,469,472,474,476,478],{"class":46,"line":128},[44,468,131],{"class":65},[44,470,471],{"class":69},"current-period-index",[44,473,117],{"class":65},[44,475,120],{"class":65},[44,477,62],{"class":61},[44,479,125],{"class":65},[44,481,482],{"class":46,"line":146},[44,483,150],{"class":149},[14,485,486,489],{},[29,487,488],{},":current-period-index"," は単方向バインディング（親→子）です。子コンポーネントは値を受け取るだけで、変更はできません。",[14,491,492],{},"子コンポーネント側：",[22,494,496],{"className":38,"code":495,"language":40,"meta":31,"style":31},"// EPSChart.vue\ninterface Props {\n  epsData: EpsDataItem[]\n  currentPeriodIndex: number\n}\n\nconst props = defineProps\u003CProps>()\n\n// props.currentPeriodIndex を使って現在の期間をハイライト\n",[29,497,498,503,513,525,534,538,542,560,564],{"__ignoreMap":31},[44,499,500],{"class":46,"line":47},[44,501,502],{"class":50},"// EPSChart.vue\n",[44,504,505,508,511],{"class":46,"line":54},[44,506,507],{"class":57},"interface",[44,509,510],{"class":251}," Props",[44,512,356],{"class":65},[44,514,515,518,520,523],{"class":46,"line":128},[44,516,517],{"class":61},"  epsData",[44,519,248],{"class":65},[44,521,522],{"class":251},"EpsDataItem",[44,524,265],{"class":65},[44,526,527,530,532],{"class":46,"line":146},[44,528,529],{"class":61},"  currentPeriodIndex",[44,531,248],{"class":65},[44,533,252],{"class":251},[44,535,536],{"class":46,"line":268},[44,537,432],{"class":65},[44,539,540],{"class":46,"line":274},[44,541,278],{"emptyLinePlaceholder":277},[44,543,544,546,548,550,552,554,557],{"class":46,"line":281},[44,545,58],{"class":57},[44,547,232],{"class":61},[44,549,66],{"class":65},[44,551,237],{"class":69},[44,553,105],{"class":65},[44,555,556],{"class":251},"Props",[44,558,559],{"class":65},">()\n",[44,561,562],{"class":46,"line":296},[44,563,278],{"emptyLinePlaceholder":277},[44,565,566],{"class":46,"line":324},[44,567,568],{"class":50},"// props.currentPeriodIndex を使って現在の期間をハイライト\n",[18,570,571],{"id":571},"データの流れ",[573,574,575,585,591,599,610],"ol",{},[576,577,578,248,582],"li",{},[579,580,581],"strong",{},"初期状態",[29,583,584],{},"microsoftPeriodIndex = 0",[576,586,587,590],{},[579,588,589],{},"ユーザー操作",": AnimationControlPanelの「次へ」ボタンをクリック",[576,592,593,248,596],{},[579,594,595],{},"emit発火",[29,597,598],{},"emit('update:modelValue', 1)",[576,600,601,248,604,606,607,609],{},[579,602,603],{},"親の状態更新",[29,605,62],{}," が ",[29,608,383],{}," に変更",[576,611,612,248,615,617,618],{},[579,613,614],{},"自動再レンダリング",[29,616,62],{}," を参照しているすべてのコンポーネントが更新される\n",[619,620,621,624,627,630],"ul",{},[576,622,623],{},"EPSChart の現在期間のハイライトが変わる",[576,625,626],{},"FCFChart の現在期間のハイライトが変わる",[576,628,629],{},"ProfitMarginChart の現在期間のハイライトが変わる",[576,631,632],{},"財務諸表の表示期間も変わる",[18,634,635],{"id":635},"なぜこの設計が良いのか",[637,638,640],"h3",{"id":639},"単一の信頼できる情報源single-source-of-truth","単一の信頼できる情報源（Single Source of Truth）",[22,642,644],{"className":38,"code":643,"language":40,"meta":31,"style":31},"// 状態は親コンポーネントで1箇所だけ管理\nconst microsoftPeriodIndex = ref(0)\n",[29,645,646,651],{"__ignoreMap":31},[44,647,648],{"class":46,"line":47},[44,649,650],{"class":50},"// 状態は親コンポーネントで1箇所だけ管理\n",[44,652,653,655,657,659,661,663,665],{"class":46,"line":54},[44,654,58],{"class":57},[44,656,62],{"class":61},[44,658,66],{"class":65},[44,660,70],{"class":69},[44,662,73],{"class":65},[44,664,77],{"class":76},[44,666,80],{"class":65},[14,668,669],{},"複数のコンポーネントが同じ状態を参照するので、常に同期が保たれます。",[637,671,672],{"id":672},"明確なデータフロー",[619,674,675,680],{},[576,676,677,679],{},[579,678,155],{},": 状態を変更できるコンポーネント（コントロールパネル）",[576,681,682,686],{},[579,683,684],{},[232,685],{},": 状態を読み取るだけのコンポーネント（チャート）",[14,688,689],{},"誰が値を変更できるかが明確になります。",[18,691,692],{"id":692},"実際のコード例",[637,694,695],{"id":695},"親コンポーネント",[22,697,699],{"className":96,"code":698,"language":98,"meta":31,"style":31},"\u003Ctemplate>\n  \u003Cdiv class=\"two-column-layout\">\n    \u003C!-- 左側: 財務諸表 + コントロール -->\n    \u003Cdiv class=\"left-column\">\n      \u003CProportionalFinancialStatementsAnimated\n        v-model=\"microsoftPeriodIndex\"\n        :companies=\"microsoftData\"\n      />\n      \u003CAnimationControlPanel\n        v-model=\"microsoftPeriodIndex\"\n        :labels=\"microsoftPeriodLabels\"\n      />\n    \u003C/div>\n\n    \u003C!-- 右側: チャート -->\n    \u003Cdiv class=\"right-column\">\n      \u003CEPSChart\n        :eps-data=\"microsoftEpsData\"\n        :current-period-index=\"microsoftPeriodIndex\"\n      />\n      \u003CFCFChart\n        :cash-flow-data=\"microsoftCashFlowData\"\n        :current-period-index=\"microsoftPeriodIndex\"\n      />\n    \u003C/div>\n  \u003C/div>\n\u003C/template>\n\n\u003Cscript setup lang=\"ts\">\nimport { ref, computed } from 'vue'\n\n// 唯一の状態管理\nconst microsoftPeriodIndex = ref(0)\n\n// チャート用のデータ（computed で期間ラベルからデータを生成）\nconst microsoftEpsData = computed(() => {\n  return company.periods.map(period => ({\n    label: period.label,\n    eps: epsDataMap[period.label] || 0\n  }))\n})\n\u003C/script>\n",[29,700,701,711,733,738,758,766,779,793,798,804,816,829,833,842,846,851,871,878,892,906,911,919,934,947,952,961,971,981,986,1011,1041,1046,1052,1069,1074,1080,1098,1127,1145,1174,1180,1186],{"__ignoreMap":31},[44,702,703,705,708],{"class":46,"line":47},[44,704,105],{"class":65},[44,706,707],{"class":108},"template",[44,709,710],{"class":65},">\n",[44,712,713,716,719,722,724,726,729,731],{"class":46,"line":54},[44,714,715],{"class":65},"  \u003C",[44,717,718],{"class":108},"div",[44,720,721],{"class":61}," class",[44,723,117],{"class":65},[44,725,120],{"class":299},[44,727,728],{"class":303},"two-column-layout",[44,730,120],{"class":299},[44,732,710],{"class":65},[44,734,735],{"class":46,"line":128},[44,736,737],{"class":50},"    \u003C!-- 左側: 財務諸表 + コントロール -->\n",[44,739,740,743,745,747,749,751,754,756],{"class":46,"line":146},[44,741,742],{"class":65},"    \u003C",[44,744,718],{"class":108},[44,746,721],{"class":61},[44,748,117],{"class":65},[44,750,120],{"class":299},[44,752,753],{"class":303},"left-column",[44,755,120],{"class":299},[44,757,710],{"class":65},[44,759,760,763],{"class":46,"line":268},[44,761,762],{"class":65},"      \u003C",[44,764,765],{"class":108},"ProportionalFinancialStatementsAnimated\n",[44,767,768,771,773,775,777],{"class":46,"line":274},[44,769,770],{"class":61},"        v-model",[44,772,117],{"class":65},[44,774,120],{"class":299},[44,776,62],{"class":303},[44,778,125],{"class":299},[44,780,781,784,786,788,791],{"class":46,"line":281},[44,782,783],{"class":61},"        :companies",[44,785,117],{"class":65},[44,787,120],{"class":299},[44,789,790],{"class":303},"microsoftData",[44,792,125],{"class":299},[44,794,795],{"class":46,"line":296},[44,796,797],{"class":65},"      />\n",[44,799,800,802],{"class":46,"line":324},[44,801,762],{"class":65},[44,803,109],{"class":108},[44,805,806,808,810,812,814],{"class":46,"line":329},[44,807,770],{"class":61},[44,809,117],{"class":65},[44,811,120],{"class":299},[44,813,62],{"class":303},[44,815,125],{"class":299},[44,817,818,821,823,825,827],{"class":46,"line":334},[44,819,820],{"class":61},"        :labels",[44,822,117],{"class":65},[44,824,120],{"class":299},[44,826,141],{"class":303},[44,828,125],{"class":299},[44,830,831],{"class":46,"line":340},[44,832,797],{"class":65},[44,834,835,838,840],{"class":46,"line":359},[44,836,837],{"class":65},"    \u003C/",[44,839,718],{"class":108},[44,841,710],{"class":65},[44,843,844],{"class":46,"line":404},[44,845,278],{"emptyLinePlaceholder":277},[44,847,848],{"class":46,"line":429},[44,849,850],{"class":50},"    \u003C!-- 右側: チャート -->\n",[44,852,854,856,858,860,862,864,867,869],{"class":46,"line":853},16,[44,855,742],{"class":65},[44,857,718],{"class":108},[44,859,721],{"class":61},[44,861,117],{"class":65},[44,863,120],{"class":299},[44,865,866],{"class":303},"right-column",[44,868,120],{"class":299},[44,870,710],{"class":65},[44,872,874,876],{"class":46,"line":873},17,[44,875,762],{"class":65},[44,877,448],{"class":108},[44,879,881,884,886,888,890],{"class":46,"line":880},18,[44,882,883],{"class":61},"        :eps-data",[44,885,117],{"class":65},[44,887,120],{"class":299},[44,889,462],{"class":303},[44,891,125],{"class":299},[44,893,895,898,900,902,904],{"class":46,"line":894},19,[44,896,897],{"class":61},"        :current-period-index",[44,899,117],{"class":65},[44,901,120],{"class":299},[44,903,62],{"class":303},[44,905,125],{"class":299},[44,907,909],{"class":46,"line":908},20,[44,910,797],{"class":65},[44,912,914,916],{"class":46,"line":913},21,[44,915,762],{"class":65},[44,917,918],{"class":108},"FCFChart\n",[44,920,922,925,927,929,932],{"class":46,"line":921},22,[44,923,924],{"class":61},"        :cash-flow-data",[44,926,117],{"class":65},[44,928,120],{"class":299},[44,930,931],{"class":303},"microsoftCashFlowData",[44,933,125],{"class":299},[44,935,937,939,941,943,945],{"class":46,"line":936},23,[44,938,897],{"class":61},[44,940,117],{"class":65},[44,942,120],{"class":299},[44,944,62],{"class":303},[44,946,125],{"class":299},[44,948,950],{"class":46,"line":949},24,[44,951,797],{"class":65},[44,953,955,957,959],{"class":46,"line":954},25,[44,956,837],{"class":65},[44,958,718],{"class":108},[44,960,710],{"class":65},[44,962,964,967,969],{"class":46,"line":963},26,[44,965,966],{"class":65},"  \u003C/",[44,968,718],{"class":108},[44,970,710],{"class":65},[44,972,974,977,979],{"class":46,"line":973},27,[44,975,976],{"class":65},"\u003C/",[44,978,707],{"class":108},[44,980,710],{"class":65},[44,982,984],{"class":46,"line":983},28,[44,985,278],{"emptyLinePlaceholder":277},[44,987,989,991,994,997,1000,1002,1004,1007,1009],{"class":46,"line":988},29,[44,990,105],{"class":65},[44,992,993],{"class":108},"script",[44,995,996],{"class":61}," setup",[44,998,999],{"class":61}," lang",[44,1001,117],{"class":65},[44,1003,120],{"class":299},[44,1005,1006],{"class":303},"ts",[44,1008,120],{"class":299},[44,1010,710],{"class":65},[44,1012,1014,1017,1020,1022,1024,1027,1030,1033,1036,1038],{"class":46,"line":1013},30,[44,1015,1016],{"class":108},"import",[44,1018,1019],{"class":65}," {",[44,1021,70],{"class":61},[44,1023,418],{"class":65},[44,1025,1026],{"class":61}," computed",[44,1028,1029],{"class":65}," }",[44,1031,1032],{"class":108}," from",[44,1034,1035],{"class":299}," '",[44,1037,98],{"class":303},[44,1039,1040],{"class":299},"'\n",[44,1042,1044],{"class":46,"line":1043},31,[44,1045,278],{"emptyLinePlaceholder":277},[44,1047,1049],{"class":46,"line":1048},32,[44,1050,1051],{"class":50},"// 唯一の状態管理\n",[44,1053,1055,1057,1059,1061,1063,1065,1067],{"class":46,"line":1054},33,[44,1056,58],{"class":57},[44,1058,62],{"class":61},[44,1060,66],{"class":65},[44,1062,70],{"class":69},[44,1064,73],{"class":65},[44,1066,77],{"class":76},[44,1068,80],{"class":65},[44,1070,1072],{"class":46,"line":1071},34,[44,1073,278],{"emptyLinePlaceholder":277},[44,1075,1077],{"class":46,"line":1076},35,[44,1078,1079],{"class":50},"// チャート用のデータ（computed で期間ラベルからデータを生成）\n",[44,1081,1083,1085,1087,1089,1091,1094,1096],{"class":46,"line":1082},36,[44,1084,58],{"class":57},[44,1086,462],{"class":61},[44,1088,66],{"class":65},[44,1090,1026],{"class":69},[44,1092,1093],{"class":65},"(()",[44,1095,353],{"class":65},[44,1097,356],{"class":65},[44,1099,1101,1104,1107,1109,1112,1114,1117,1119,1122,1124],{"class":46,"line":1100},37,[44,1102,1103],{"class":108},"  return",[44,1105,1106],{"class":61}," company",[44,1108,375],{"class":65},[44,1110,1111],{"class":61},"periods",[44,1113,375],{"class":65},[44,1115,1116],{"class":69},"map",[44,1118,73],{"class":65},[44,1120,1121],{"class":61},"period",[44,1123,353],{"class":65},[44,1125,1126],{"class":65}," ({\n",[44,1128,1130,1133,1135,1137,1139,1142],{"class":46,"line":1129},38,[44,1131,1132],{"class":400},"    label",[44,1134,248],{"class":65},[44,1136,1121],{"class":61},[44,1138,375],{"class":65},[44,1140,1141],{"class":61},"label",[44,1143,1144],{"class":65},",\n",[44,1146,1148,1151,1153,1156,1159,1161,1163,1165,1168,1171],{"class":46,"line":1147},39,[44,1149,1150],{"class":400},"    eps",[44,1152,248],{"class":65},[44,1154,1155],{"class":61},"epsDataMap",[44,1157,1158],{"class":65},"[",[44,1160,1121],{"class":61},[44,1162,375],{"class":65},[44,1164,1141],{"class":61},[44,1166,1167],{"class":65},"] ",[44,1169,1170],{"class":57},"||",[44,1172,1173],{"class":76}," 0\n",[44,1175,1177],{"class":46,"line":1176},40,[44,1178,1179],{"class":65},"  }))\n",[44,1181,1183],{"class":46,"line":1182},41,[44,1184,1185],{"class":65},"})\n",[44,1187,1189,1191,1193],{"class":46,"line":1188},42,[44,1190,976],{"class":65},[44,1192,993],{"class":108},[44,1194,710],{"class":65},[637,1196,1198],{"id":1197},"子コンポーネントチャート","子コンポーネント（チャート）",[22,1200,1202],{"className":96,"code":1201,"language":98,"meta":31,"style":31},"\u003Ctemplate>\n  \u003Csvg>\n    \u003Ccircle\n      v-for=\"(point, index) in dataPoints\"\n      :key=\"index\"\n      :cx=\"point.x\"\n      :cy=\"point.y\"\n      :r=\"index === currentPeriodIndex ? 7 : 4\"\n      :fill=\"index === currentPeriodIndex ? '#ff6b6b' : '#4caf50'\"\n    />\n  \u003C/svg>\n\u003C/template>\n\n\u003Cscript setup lang=\"ts\">\ninterface Props {\n  epsData: { label: string; eps: number }[]\n  currentPeriodIndex: number  // 親から渡される現在の期間\n}\n\nconst props = defineProps\u003CProps>()\n\n// currentPeriodIndex を使って現在選択中の期間を大きく・赤く表示\n\u003C/script>\n",[29,1203,1204,1212,1221,1228,1242,1256,1270,1284,1298,1312,1317,1325,1333,1337,1357,1365,1391,1402,1406,1410,1426,1430,1435],{"__ignoreMap":31},[44,1205,1206,1208,1210],{"class":46,"line":47},[44,1207,105],{"class":65},[44,1209,707],{"class":108},[44,1211,710],{"class":65},[44,1213,1214,1216,1219],{"class":46,"line":54},[44,1215,715],{"class":65},[44,1217,1218],{"class":108},"svg",[44,1220,710],{"class":65},[44,1222,1223,1225],{"class":46,"line":128},[44,1224,742],{"class":65},[44,1226,1227],{"class":108},"circle\n",[44,1229,1230,1233,1235,1237,1240],{"class":46,"line":146},[44,1231,1232],{"class":61},"      v-for",[44,1234,117],{"class":65},[44,1236,120],{"class":299},[44,1238,1239],{"class":303},"(point, index) in dataPoints",[44,1241,125],{"class":299},[44,1243,1244,1247,1249,1251,1254],{"class":46,"line":268},[44,1245,1246],{"class":61},"      :key",[44,1248,117],{"class":65},[44,1250,120],{"class":299},[44,1252,1253],{"class":303},"index",[44,1255,125],{"class":299},[44,1257,1258,1261,1263,1265,1268],{"class":46,"line":274},[44,1259,1260],{"class":61},"      :cx",[44,1262,117],{"class":65},[44,1264,120],{"class":299},[44,1266,1267],{"class":303},"point.x",[44,1269,125],{"class":299},[44,1271,1272,1275,1277,1279,1282],{"class":46,"line":281},[44,1273,1274],{"class":61},"      :cy",[44,1276,117],{"class":65},[44,1278,120],{"class":299},[44,1280,1281],{"class":303},"point.y",[44,1283,125],{"class":299},[44,1285,1286,1289,1291,1293,1296],{"class":46,"line":296},[44,1287,1288],{"class":61},"      :r",[44,1290,117],{"class":65},[44,1292,120],{"class":299},[44,1294,1295],{"class":303},"index === currentPeriodIndex ? 7 : 4",[44,1297,125],{"class":299},[44,1299,1300,1303,1305,1307,1310],{"class":46,"line":324},[44,1301,1302],{"class":61},"      :fill",[44,1304,117],{"class":65},[44,1306,120],{"class":299},[44,1308,1309],{"class":303},"index === currentPeriodIndex ? '#ff6b6b' : '#4caf50'",[44,1311,125],{"class":299},[44,1313,1314],{"class":46,"line":329},[44,1315,1316],{"class":65},"    />\n",[44,1318,1319,1321,1323],{"class":46,"line":334},[44,1320,966],{"class":65},[44,1322,1218],{"class":108},[44,1324,710],{"class":65},[44,1326,1327,1329,1331],{"class":46,"line":340},[44,1328,976],{"class":65},[44,1330,707],{"class":108},[44,1332,710],{"class":65},[44,1334,1335],{"class":46,"line":359},[44,1336,278],{"emptyLinePlaceholder":277},[44,1338,1339,1341,1343,1345,1347,1349,1351,1353,1355],{"class":46,"line":404},[44,1340,105],{"class":65},[44,1342,993],{"class":108},[44,1344,996],{"class":61},[44,1346,999],{"class":61},[44,1348,117],{"class":65},[44,1350,120],{"class":299},[44,1352,1006],{"class":303},[44,1354,120],{"class":299},[44,1356,710],{"class":65},[44,1358,1359,1361,1363],{"class":46,"line":429},[44,1360,507],{"class":57},[44,1362,510],{"class":251},[44,1364,356],{"class":65},[44,1366,1367,1369,1372,1374,1376,1378,1381,1384,1386,1388],{"class":46,"line":853},[44,1368,517],{"class":61},[44,1370,1371],{"class":65},": { ",[44,1373,1141],{"class":61},[44,1375,248],{"class":65},[44,1377,262],{"class":251},[44,1379,1380],{"class":65},"; ",[44,1382,1383],{"class":61},"eps",[44,1385,248],{"class":65},[44,1387,318],{"class":251},[44,1389,1390],{"class":65}," }[]\n",[44,1392,1393,1395,1397,1399],{"class":46,"line":873},[44,1394,529],{"class":61},[44,1396,248],{"class":65},[44,1398,318],{"class":251},[44,1400,1401],{"class":50},"  // 親から渡される現在の期間\n",[44,1403,1404],{"class":46,"line":880},[44,1405,432],{"class":65},[44,1407,1408],{"class":46,"line":894},[44,1409,278],{"emptyLinePlaceholder":277},[44,1411,1412,1414,1416,1418,1420,1422,1424],{"class":46,"line":908},[44,1413,58],{"class":57},[44,1415,232],{"class":61},[44,1417,66],{"class":65},[44,1419,237],{"class":69},[44,1421,105],{"class":65},[44,1423,556],{"class":251},[44,1425,559],{"class":65},[44,1427,1428],{"class":46,"line":913},[44,1429,278],{"emptyLinePlaceholder":277},[44,1431,1432],{"class":46,"line":921},[44,1433,1434],{"class":50},"// currentPeriodIndex を使って現在選択中の期間を大きく・赤く表示\n",[44,1436,1437,1439,1441],{"class":46,"line":936},[44,1438,976],{"class":65},[44,1440,993],{"class":108},[44,1442,710],{"class":65},[18,1444,1445],{"id":1445},"まとめ",[1447,1448,1449,1464],"table",{},[1450,1451,1452],"thead",{},[1453,1454,1455,1459,1462],"tr",{},[1456,1457,1458],"th",{},"用途",[1456,1460,1461],{},"記法",[1456,1463,571],{},[1465,1466,1467,1481,1493],"tbody",{},[1453,1468,1469,1473,1478],{},[1470,1471,1472],"td",{},"状態の定義",[1470,1474,1475],{},[29,1476,1477],{},"ref(初期値)",[1470,1479,1480],{},"-",[1453,1482,1483,1486,1490],{},[1470,1484,1485],{},"双方向バインディング",[1470,1487,1488],{},[29,1489,155],{},[1470,1491,1492],{},"親 ⇄ 子",[1453,1494,1495,1498,1503],{},[1470,1496,1497],{},"読み取り専用バインディング",[1470,1499,1500],{},[29,1501,1502],{},":props",[1470,1504,1505],{},"親 → 子",[14,1507,1508,1509,1512],{},"Vueのリアクティビティシステムにより、",[29,1510,1511],{},"ref"," で定義した値が変更されると、この値を参照しているすべてのコンポーネントが自動的に更新されます。これが「宣言的UI」の核心部分です。",[1514,1515,1516],"style",{},"html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html pre.shiki code .s4oTP, html code.shiki .s4oTP{--shiki-default:#B07D48;--shiki-dark:#B07D48}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .sM54T, html code.shiki .sM54T{--shiki-default:#2F798A;--shiki-dark:#2F798A}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHkkW, html code.shiki .sHkkW{--shiki-default:#1E754F;--shiki-dark:#1E754F}html pre.shiki code .sG7-3, html code.shiki .sG7-3{--shiki-default:#393A34;--shiki-dark:#393A34}html pre.shiki code .sSkh3, html code.shiki .sSkh3{--shiki-default:#2E8F82;--shiki-dark:#2E8F82}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .sz8Xr, html code.shiki .sz8Xr{--shiki-default:#998418;--shiki-dark:#998418}",{"title":31,"searchDepth":54,"depth":54,"links":1518},[1519,1520,1521,1522,1523,1524,1528,1532],{"id":20,"depth":54,"text":20},{"id":34,"depth":54,"text":35},{"id":92,"depth":54,"text":93},{"id":435,"depth":54,"text":436},{"id":571,"depth":54,"text":571},{"id":635,"depth":54,"text":635,"children":1525},[1526,1527],{"id":639,"depth":128,"text":640},{"id":672,"depth":128,"text":672},{"id":692,"depth":54,"text":692,"children":1529},[1530,1531],{"id":695,"depth":128,"text":695},{"id":1197,"depth":128,"text":1198},{"id":1445,"depth":54,"text":1445},null,"ref、v-model、propsを使ったコンポーネント間のデータ連携を解説","md",{},"/vue-reactivity-props-binding",false,"2025-12-10T00:00:00.000Z",{"title":5,"description":1534},"2025-12/2025-12-10/vue-reactivity-props-binding",[1543,1544,232,155],"Vue3","リアクティビティ","mOlZttmAm7t5oEI1qcjzGcQRlC7TumO3QzzdlTDw0LY",[],[1548,1552,1556,1560,1564],{"title":1549,"path":1550,"publishedAt":1551},"/memory-makers を半導体サプライチェーン観測ページに作り変える（Foxconn月次・Nanya追加・DRAM分類マトリックス）","/memory-makers-network-expansion","2026-06-04T00:00:00.000Z",{"title":1553,"path":1554,"publishedAt":1555},"eurekapu-nuxt4 全77ページ2カラム化 + Part 2 投資判断クイズ + 教科書 CH8-12 実装","/eurekapu-2col-and-part2-textbook","2026-05-15T00:00:00.000Z",{"title":1557,"path":1558,"publishedAt":1559},"Electron×Vue3で作るリアルタイム文字起こしアプリ「即録くん」の開発記録","/sokuroku-electron-development","2026-03-19T00:00:00.000Z",{"title":1561,"path":1562,"publishedAt":1563},"2026年2月18日の開発日記 - 音アーカイブの方向転換と大量実装","/2026-02-18-diary","2026-02-18T00:00:00.000Z",{"title":1565,"path":1566,"publishedAt":1563},"音アーカイブサイト開発と浅草フィールドレコーディング - TASCAM音源追加・山手線プロト・マップ拡充","/oto-archive-dev-2026-02-18","https://log.eurekapu.com/og/blog/vue-reactivity-props-binding.png?v=2025-12-10T00%3A00%3A00.000Z&title=Vue%203%E3%81%AE%E3%83%AA%E3%82%A2%E3%82%AF%E3%83%86%E3%82%A3%E3%83%93%E3%83%86%E3%82%A3%E3%81%A8props%E3%83%90%E3%82%A4%E3%83%B3%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF&author=Kei%20Komatsu&sig=0a05394a70da9bf0",1785654674983]