-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide/Inject outside setup #6220
Comments
"Global provide/inject API" could not exists by design. Provide/Inject works in component's subtree in Vue App. Value is provided in one instance in one place of tree and injected in another instance in any place of subtree. In simple words, injected value depends on all upper tree and may be various in different places of the component's tree or even in different Vue apps on the page. const app1 = createApp(App).provide('key', 'foo');
const app2 = createApp(App).provide('key', 'bar');
globalInject('key'); // ? foo or bar ? If you need "global provide/inject" you might either not need provide/inject at all or need to provide some global value instead. So if you need There may be dozens ways to do it in JavaScript from simple ES Modules with global reactive variables or global store to IoC container. For example, a simple solution with global variable without provide/inject: // 📁 darkMode.js
import { ref, readolny } from 'vue';
export const isDarkMode = ref(false);
export function getDarkModeSetting() {
return isDarkMode.value;
}
export function toggleDarkModeSettings(newMode) {
isDarkMode.value = newMode;
} // 📁 Literally any place of app, inc. setup
import { darkMode } from './path/to/darkMode.js';
const { getDarkMode, toggleDarkMode } = darkMode; Or you may use approach similar to Vue Router or Vuex plugins. First create thing globally, then provide it. Create scope with dark mode functionality: // 📁 createDarkMode.js
import { ref, readolny } from 'vue';
export function createDarkMode(initial) {
const isDarkMode = ref(initial);
function getDarkModeSetting() {
return isDarkMode.value;
}
function toggleDarkModeSettings(newMode) {
isDarkMode.value = newMode;
}
return {
isDarkMode: readonly(isDarkMode),
getDarkModeSetting,
toggleDarkModeSettings,
};
} Create global dark mode: // 📁 darkMode.js
import { createDarkMode } from './path/to/createDarkMode.js';
export const darkMode = createDarkMode(false); Provide global dark mode to Vue app: // 📁 main.js
import { darkMode } from './path/to/darkMode.js';
const app = createApp(App).provide('DARK_MODE', darkMode); Inject as usual in components: // 📁 SomeComponent.vue
const { isDarkMode, toggleDarkMode } = inject('DARK_MODE'); ...or use in any other ES module in the app without provide/inject: // 📁 any place
import { darkMode } from './path/to/darkMode.js';
const { getDarkMode, toggleDarkMode } = darkMode; |
I don't understand the request here. Your use case doesn't seem to require FYI there's app-level provide: https://vuejs.org/api/application.html#app-provide |
I think I may have not explained myself properly. I am using the provide/inject inside a component, but in the |
You can use Pinia state management to achieve global provide/inject. It is just easier.More details here |
You can still do the injection in setup and then check the result in the hook. No need for any new API. setup() {
const prefersDarMode = inject('darkModeCheck')
onMounted(() => {
// assuming you provided a ref.
if (prefersDarkMode.value === true) {
// do something
}
})
} |
My main problem is not with the inject but rather with the provide, as I need to provide the value based on media queries, which I can only access through the document in the onMounted hook. |
|
I think you mistook "provide" as a method to provide a default value rather than to create a store for later use. |
I definitely mistook the wording "provide", "inject" to mean exactly that, set and read values. I was using pinia because of this misunderstanding. |
I'm creating a Vue plugin. If I do this: const options = inject<PluginOptions>(PLUGIN_KEY);
const props = withDefaults(defineProps<Props>(), {
expanded: false,
duration: options?.duration || 300,
hwAcceleration: options?.hwAcceleration || false,
}); I get this warning:
But if I hoist it as mentioned like so: <script lang="ts">
const options = inject<PluginOptions>(PLUGIN_KEY);
</script>
<script setup lang="ts">
const props = withDefaults(defineProps<Props>(), {
expanded: false,
duration: options?.duration || 300,
hwAcceleration: options?.hwAcceleration || false,
});
</script> I get this error instead:
It seems to me that being able to use |
@mrleblanc101 const options = inject<PluginOptions>(PLUGIN_KEY);
const props = withDefaults(defineProps<Props>(), {
expanded: false,
duration: undefined,
hwAcceleration: undefined,
});
const duration = props.duration ?? options?.duration ?? 300
const hwAcceleration = props.hwAcceleration ?? options?.hwAcceleration ?? false
// (or wrap them in `computed` so they become reactive) So props are no longer dependent on local variables. |
@UnluckyNinja Thanks for your time, I found this one while doing research and it felt pretty close to what I needed to solve my issue (a global inject), also opened a new issue because I might have found a bug related to the alternative someone suggested me (use inject inside the props default factory function) #7677 Your solution is probably what I will end up doing, but I wanted to keep the default value inside the withDefault because it make more sense. It's kinda weird to use withDefault but not providing a default value and having to use 2 other variables/computed to achieve the same thing. |
What problem does this feature solve?
As of now, the
provide
andinject
methods only work in the context of the component setup, but they could also be really useful outside that context.For example a case that I'm facing. I have an app where I want to check if the user wants dark mode when the app is opened, either via a setting that you can change in the app or by media queries in case the setting is not configured. So the part that loads and sets the dark mode preference in
App.vue
looks something like this:Then in my settings page, I could have a switch that takes as initial value whether the dark mode is loaded or not:
What does the proposed API look like?
There isn't any change in API needed in theory, just enabling the API to work outside the setup hook.
The text was updated successfully, but these errors were encountered: