DEV Community

Aissa BOUGUERN
Aissa BOUGUERN

Posted on

2 1

I have a problem with Vue composition API

Hi,
I'm trying to create a vue composable hook to toggle sidebar menu.

import { reactive, toRefs } from '@vue/composition-api';

const useToggleMenu = () => {
  const state = reactive({
    isMenuOpen: true,
  });

  const toggleMenu = () => {
    state.isMenuOpen = !state.isMenuOpen;
  };

  return {
    ...toRefs(state),
    toggleMenu,
  };
};

export default useToggleMenu;

the problem I'm facing is when using isMenuOpen state in one component (ex: Layout), and use toggleMenu in another component (ex: BurgerMenu).

// BurgerMenu.vue

import { useToggleMenu } from '../hooks';

export default {
  name: 'BurgerMenu',
  setup() {
    const { toggleMenu } = useToggleMenu();
    return {
      // use this in template to show/hide menu.
      toggleMenu,
    };
  },

  ...
};
// Layout.vue

import { useToggleMenu } from '../hooks';

export default {
  name: 'Layout',
  setup() {
    const { isMenuOpen } = useToggleMenu();

    return {
      // use this in template to add some classes to <body>
      isMenuOpen,
    };
  },
};

  ...
};

the issue is when I click burger menu and trigger the toggleMenu function, that does not make any change! the isMenuOpen boolean is not reactive.

I hope that is clear, and thanks to anyone trying to help.

Image of Bright Data

Ensure Data Quality Across Sources – Manage and normalize data effortlessly.

Maintain high-quality, consistent data across multiple sources with our efficient data management tools.

Manage Data

Top comments (4)

Collapse
 
alexanderjanke profile image
Alex Janke

Do you mean it is not reactive that the state doesn't sync between your BurgerMenu.vue and in your Layout.vue? That is correct. Each time you call useToggleMenu() you basically create your own scope of that function, so they can run in parallel without interfering with eachother.

Check this codesandbox to see what I mean:
Codesandbox
Here I copied your code. I only changed the reactive to ref because a single value is better suited in a ref(). As you can see here the code is reactive but the two implementations do not sync.

Also you do not need to put the state in toRefs() when returning

Collapse
 
aissabouguern profile image
Aissa BOUGUERN • Edited

Thank you Alex,
Yes i now understand what's the problem,
I need to put some mechanism to share that state between those components. something like useContext in React.js

Collapse
 
alexanderjanke profile image
Alex Janke

Normally you can just move the state out of the function.
Something like

export const state = ref(false)
export const toggleMenu = () => {
  state.value = !state.value;
}

Not tested but this should work I think

Collapse
 
emanuelaguilar74 profile image
Emanuel

Hi!
The problem is that every time you call it, your composable is creating a new scope. There are many ways to solve this problem.
You can use the composable on a component that is parent of Layout and BurgerMenu, then pass props to them and emit events for the parent to execute the changes on the state.
Another way is to using provide/inject, this is kinda similar to useContext in react.
Sorry if my english is not good enough.
Good luck!

Image of AssemblyAI

Automatic Speech Recognition with AssemblyAI

Experience near-human accuracy, low-latency performance, and advanced Speech AI capabilities with AssemblyAI's Speech-to-Text API. Sign up today and get $50 in API credit. No credit card required.

Try the API

👋 Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay