Asked 1 month ago by QuasarCosmonaut351
How can I toggle a search bar in Vue using reactive refs like React’s useState?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by QuasarCosmonaut351
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
I'm trying to implement a toggle feature where clicking a button makes a search bar appear and disappear. However, my Vue code doesn't work as expected, and I'm unsure why. I've been comparing this to React's useState hook, and I suspect the issue might involve how I'm handling Vue's reactive refs.
Here's the code I'm working with:
VUE<template> <button @click="toggleSearchBar" v-if="! searchBarOpen" > Open Search bar </button> <div v-else > <input /> <button @click="toggleSearchBar" > </button> </div> <template> <script setup> import { ref } from "vue"; let searchBarOpen = ref(false); const toggleSearchBar = () => { if (searchBarOpen) { searchBarOpen = false; } else { searchBarOpen = true; } console.log({ searchBarOpen }); }; </script>
Comments 0
•Answers 5
•Views 82
Answer by TychoAI Agent • 1 month ago
Your issue stems from how you're using the Vue ref. In the script, you're creating a reactive reference with:
JSlet searchBarOpen = ref(false);
To check or update the value of a ref, you must use its .value
property. Instead of doing:
JSif (searchBarOpen) { searchBarOpen = false; } else { searchBarOpen = true; }
you should do:
JSif (searchBarOpen.value) { searchBarOpen.value = false; } else { searchBarOpen.value = true; }
An even more concise toggle would be:
JSconst toggleSearchBar = () => { searchBarOpen.value = !searchBarOpen.value; console.log({ searchBarOpen: searchBarOpen.value }); };
The Vue template automatically unwraps refs, which is why you can use searchBarOpen
directly in your template. Just remember to use .value
in your script when reading or writing its value.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
Answer by SolarCommander777 • 1 month ago
That's all
VUE<template> <button @click="() => searchBarOpen = !searchBarOpen" > {{ searchBarOpen ? 'Close search bar' : 'Open search bar' }} </button> <input v-if="searchBarOpen"/> <template> <script setup> import { ref } from "vue"; const searchBarOpen = ref(false); </script>
No comments yet.
Answer by StellarSentinel584 • 1 month ago
Although I wrote an answer based on the typo in the question, I will specifically answer the question now.
If we have understood Vue reactivity and still want to accomplish something interesting like this, let's continue.
The React useState
hook returns two values: the readonly
current state and a function to update the reactive stored variable.
JAVASCRIPTconst [state, setState] = useState(initialValue);
In Vue, we can create a function called useState
, where we initialize a ref, return it as readonly
, and define a setState
function to modify the stored ref value.
JAVASCRIPTimport { ref, readonly } from 'vue'; function useState(initialValue) { const state = ref(initialValue); const setState = (newValue) => { if (typeof newValue === "function") { state.value = newValue(state.value); } else { state.value = newValue; } }; return [readonly(state), setState]; }
This useState
function provides a similar experience in Vue, allowing you to use it in the same way.
JAVASCRIPTimport { useState } from './useState.js'; const [count, setCount] = useState(0); const increment = () => setCount((prev) => prev + 1);
Live Vue CDN Example
JAVASCRIPTconst { createApp, ref, readonly } = Vue; // Custom useState function function useState(initialValue) { const state = ref(initialValue); const setState = (newValue) => { if (typeof newValue === "function") { state.value = newValue(state.value); } else { state.value = newValue; } }; return [readonly(state), setState]; } // Vue app setup const app = createApp({ setup() { const [openStatus, setOpenStatus] = useState(false); const [count, setCount] = useState(0); const toggleOpenStatus = () => setOpenStatus((status) => ! status) const increment = () => setCount(prev => prev + 1); return { openStatus, toggleOpenStatus, count, increment }; }, template: `< <div>< <button v-if="! openStatus" @click="toggleOpenStatus">Open</button>< <div v-else>< <p>Count: {{ count }}</p>< <button @click="increment">Increment</button>< <button @click="toggleOpenStatus">Close</button>< </div>< </div>< `, }); app.mount("#app");
HTML<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script> <div id="app"></div>
Run code snippetHide resultsExpand snippet
Here is a React example as well.
Show code snippet
JAVASCRIPTconst { useState } = React; function App() { const [openStatus, setOpenStatus] = useState(false); const [count, setCount] = useState(0); const toggleOpenStatus = () => setOpenStatus(prevStatus => ! prevStatus); const increment = () => setCount(prev => prev + 1); return ( <div> {! openStatus ? ( <button onClick={toggleOpenStatus}>Open</button> ) : ( <div> <p>Count: {count}</p> <button onClick={increment}>Increment</button> <button onClick={toggleOpenStatus}>Close</button> </div> )} </div> ); } ReactDOM.createRoot(document.getElementById("root")).render(<App />);
HTML<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script> <div id="root"></div>
Run code snippetHide resultsExpand snippet
No comments yet.
Answer by MartianMariner067 • 1 month ago
Live example with React CDN
Show code snippet
JAVASCRIPTconst { useState } = React; function App() { const [searchBarOpen, setSearchBarOpen] = useState(false); return ( <div> {!searchBarOpen ? ( <button onClick={() => setSearchBarOpen(true)}>Open Search Bar</button> ) : ( <div> <input /> <button onClick={() => setSearchBarOpen(false)}>Close</button> </div> )} </div> ); } ReactDOM.createRoot(document.getElementById("root")).render(<App />);
HTML<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script> <div id="root"></div>
Run code snippetHide resultsExpand snippet
In Vue, you can declare reactive objects using the ref()
function. You can read or modify their data through the .value
property.
ref()
function - Vue 3 Docsreactive()
function - Vue 3 Docsref()
vs reactive()
in Vue 3 - StackOverflowref()
, toRef()
and toRefs()
? - StackOverflowYourComponent.vue (Composition API, Vue 3)
HTML<template> <div> <button v-if="!searchBarOpen" @click="toggleSearchBar"> Open Search Bar </button> <div v-else> <input /> <button @click="toggleSearchBar">Close</button> </div> </div> </template> <script setup> const searchBarOpen = ref(false); const toggleSearchBar = () => { searchBarOpen.value = ! searchBarOpen.value; }; </script>
Live example with Vue CDN
Show code snippet
JAVASCRIPTconst { createApp, ref } = Vue; createApp({ setup() { const searchBarOpen = ref(false); const toggleSearchBar = () => { searchBarOpen.value = ! searchBarOpen.value; }; return { searchBarOpen, toggleSearchBar }; }, template: `< <div> <button v-if="!searchBarOpen" @click="toggleSearchBar"> Open Search Bar </button> <div v-else> <input /> <button @click="toggleSearchBar">Close</button> </div> </div> `< }).mount("#app");
HTML<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script> <div id="app"></div>
Run code snippetHide resultsExpand snippet
No comments yet.
Answer by StellarGuide940 • 1 month ago
You simply need to set
searchBarOpen.value = true
(or false)
The value property in Vue refs is needed for reactivity internally.
In templates however, your reference to searchBarOpen is correct without value, because the value property will be unwrapped under the hood.
No comments yet.
No comments yet.