Writing reusable code with Vue3 composition api
Tags: vue, vue3, javascript, webdev
Published: 2023-02-08 12:13:16

Composition api in Vue3 helps to write reusable logic.

When I wrote it myself, I thought it was similar to a React hook.

I have written codes to reuse the logic that fetch data from supabase and extract "korean_name" property of it.

```js
// @/modules/useKoreanName.js
import { supabase } from '@/utils/supabase'
import { reactive, toRefs } from 'vue'

export default function useUserKoreanName() {
  const state = reactive({
    userKoreanName: '이름',
  })
  const loadUserKoreanName = async id => {
    const koreanName = await fetchUserKoreanName(id)
    if (koreanName) state.userKoreanName = koreanName
  }
  const fetchUserKoreanName = async id => {
    try {
      const { data: users } = await supabase
        .from('users')
        .select('korean_name')
        .eq('id', id)
      if (users) {
        return users[0].korean_name
      }
    } catch (error) {
      console.error(error)
    }
  }
  return { ...toRefs(state), fetchUserKoreanName, loadUserKoreanName }
}
```

What we should pay attention to is that the code returned state `in the form of toRefs(state)`. I heard that this is how we maintain its responsiveness. I imported this module in another component to use it.

```js
const { userKoreanName, loadUserKoreanName } = useKoreanName();

onMounted(() => {
  fetchNotes();
  loadUserKoreanName(id);
});

...
    <div class="text-4xl mr-4">{{ userKoreanName }} 님 담벼락</div>

```

The template prints userKoreanName, and you can see that it works well as shown below. (It is my name in Korean)

<img width="210" alt="image" src="https://user-images.githubusercontent.com/32301380/217270090-637770b3-9f26-46b4-8950-b5f33dde0c37.png">

What if we take out toRefs?


```js
// @/modules/useKoreanName.js
import { supabase } from '@/utils/supabase'
import { reactive } from 'vue'

export default function useUserKoreanName() {
  const state = reactive({
    userKoreanName: '이름',
  })
  const loadUserKoreanName = async id => {
    const koreanName = await fetchUserKoreanName(id)
    if (koreanName) state.userKoreanName = koreanName
    console.info('koreanName after load : ', state.userKoreanName)
  }
  const fetchUserKoreanName = async id => {
    try {
      const { data: users } = await supabase
        .from('users')
        .select('korean_name')
        .eq('id', id)
      if (users) {
        return users[0].korean_name
      }
    } catch (error) {
      console.error(error)
    }
  }
  return { ...state, fetchUserKoreanName, loadUserKoreanName }
}
```

In this case, if you take a log, the state is reactive inside the useUserKoreanName function.

<img width="437" alt="image" src="https://user-images.githubusercontent.com/32301380/217271719-847b1c3c-09d9-4d33-92a0-bc05df2831be.png">

However, if you output userKoreanName from the component, you can see that it contains the default value.

<img width="183" alt="image" src="https://user-images.githubusercontent.com/32301380/217269520-8c1f4676-3cab-4378-9a37-9cadf8529259.png">

[Official document about toRefs](https://vuejs.org/api/reactivity-utilities.html#torefs)
According to the official document, when `toRefs` returns a reactive object in a composite function, the component used does not lose its reactivity even if the object is destructed or spreaded.