Search code examples
javascriptvue.jsvuejs3nuxt.jsnuxt3.js

Nuxt 3 sometimes I can omit .value when using useState, sometimes I can't, why?


Please see this minimum example, if I use useState , normally, I can write something like this:

<script setup>
const num = useState('num', () => 1);
</script>

<template>
  <div>
    {{ num }}
  </div>

  <div>
    {{ typeof num }}
  </div>

  <div>
    {{ JSON.stringify(num) }}
  </div>
</template>

And the result is what I expected:

1
number
1

enter image description here

However, when I move the useState into composables, everything changed, like this:

export const useNum = () => {
  const num = useState('num', () => 1);

  return {
    num,
  };
};
<script setup>
const numStore = useNum();
</script>

<template>
  <div>
    {{ numStore.num }}
  </div>

  <div>
    {{ typeof numStore.num }}
  </div>

  <pre>
    {{ JSON.stringify(numStore.num, null, 2) }}
  </pre>
</template>

the result is super weird:

1
object
    {
  "_object": {
    "$s__nuxt_devtools__": {
      "timeSsrStart": 1719387436211
    },
    "$snum": 1
  },
  "_key": "$snum",
  "__v_isRef": true
}
  

enter image description here

enter image description here

Why is this happening? How can I avoid this?


Solution

  • Based on official docs :

    Ref unwrapping in templates only applies if the ref is a top-level property in the template render context.

    By unwrapping we mean not using .value

    So try to destruct the return value of your composable to make the ref as top-level property or use the .value in template :

    <script setup>
    const { num } = useNum();
    </script>
    
    <template>
      <div>
        {{ num }}
      </div>
    
      <div>
        {{ typeof num }}
      </div>
    
      <pre>
        {{ JSON.stringify(num, null, 2) }}
      </pre>
    </template>