Follow the official example to export your own useStore, and then use it in the component.
import { createStore, Store, useStore as baseUseStore } from 'vuex';
export const key: InjectionKey<Store<RootState>> = Symbol();
export function useStore() {
return baseUseStore(key);
}
use in the component
setup() {
const store = useStore();
const onClick = () => {
console.log(store)
store.dispatch('user/getUserInfo');
}
return {
onClick,
}
},
After running, store is undefined.
It can be obtained normally when I use it in the methods attribute
methods: {
login() {
this.$store.dispatch('user/getToken')
}
}
why? how to fix it
In that simplifying useStore usage tutorial, you still need to register the store and key in main.ts as they did. You will get undefined if you don't do this:
// main.ts
import { store, key } from './store'
const app = createApp({ ... })
// pass the injection key
app.use(store, key)
The reason is that baseUseStore(key) has no meaning until that's done.
Related
I havent been able to figure out what the problem is here. I am using vue 3.
I trye to add an obejct to another object inside of the store state. I can add it to the firebase console, but the only thing that has not been solved yet is how to add it to the store in the state.coaches as an object within an object. In this way I would be able to display the list of object into the view of the screen.
//store-coach.js
import Vue from 'vuex'
import { uid, Notify } from 'quasar'
import firebase from 'boot/firebase'
const state = {
coaches: {
}
}
const mutations = {
addCoach(state, coach) {
Vue.set(state.coaches, coach.id, coach.coach)
}
}
const actions = {
fbReadDataCoaches({ commit }) {
let coachesfb = firebase.database().ref('coaches')
//child added
coachesfb.on('child_added',snapshot => {
let coachfb = snapshot.val()
let payload = {
id: snapshot.key,
coach: coachfb
}
commit('addCoach', payload)
})
},
fbaddCoach({}, payload){
let coachRef = firebase.database().ref('coaches/' + payload.id)
coachRef.set(payload.coach, error =>{
if(!error){
Notify.create('Coach added!!')
}
})
}
}
//index.js
import Vuex from 'vuex'
import coaches from './store-coach'
export default function (/* { ssrContext } */) {
const Store = new Vuex.Store({
modules: {
coaches
}
})
return Store
}
The error that I get is when
Vue.set(state.coaches, coach.id, coach.coach) is fired
Uncaught TypeError: vuex__WEBPACK_IMPORTED_MODULE_3__.default.set is not a function
thanks in advance!
Appreciate your time!
In first file (store-coach.js), change:-
From -
import Vue from 'vuex'
To -
import Vue from 'vue'
As .set method is available in vue package. Its not available in vuex package that is why you are getting this error. Documentation reference.
I have the following file which is an external file with functions (language.js). I also have created a other component which needs to use language.js (it needs to use the languageText funcion inside language.js). I did used it in a Composition API component. But now I want to get it working in a Options API component. Please check the function inside methods called languageSelector. Inside this function I want to use the global function from language.js (languageText())
Any help?
Options API template (Form.vue)
<script>
import languageText from '#/composables/language';
export default defineComponent({
name: 'Form',
props: {
processingData: Object,
formData: Object
},
emits: ["gateway"],
components: {
Icon
},
data() {
return {
fieldData: this.formData,
}
},
methods: {
languageSelector(data) {
const h = languageText(data) **I want to USE the FUNCTION here.**
console.log(h)
return languageText(data)
},
}
language.js
import { ref, computed, watch } from 'vue';
import { useI18n } from "vue-i18n";
import { useStore } from "vuex";
export default function language() {
const store = useStore();
const i18n = useI18n();
const language = computed(() => {
return store.getters.currentUser.language;
});
function languageText(json) {
const obj = JSON.parse(json)
return obj[language.value]
}
return {
languageText
}
}
In the code below I would like to know, how to export the function setFormData. In other words also I would like to know how to import setFormData from a different typescript file. Thank you
File A
import { SyntheticEvent } from 'react';
import { useDispatch } from 'react-redux';
import { useStatusActions } from '../../actions';
export const StatusHelper = () => {
const dispatch = useDispatch();
let statusActions = useStatusActions(dispatch);
const setFormData = (event: SyntheticEvent, key: any, value: any) => {
statusActions.setFormData(key, value);
};
File B
import {
setFormData,
} from './fileA';
you will need to create a custom hook if you want to export a function that relies on another hook. You can't simply export and use it outside react.
you should have a useStatusHelper hook that returns a setFormData function
check how to create custom hooks here
I have a NextJS React app that uses the next-react-wrapper (basically a HOC) on _app.tsx like so:
_app.tsx
...
import withRedux from 'next-redux-wrapper';
class Page extends App<Props> {
...
}
export default withRedux(reduxStore)(Page);
store.ts
import { applyMiddleware, createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly';
import rootReducer from './reducer';
export default (
initialState: any = undefined,
) => createStore(
rootReducer,
initialState,
composeWithDevTools(applyMiddleware()),
);
I'm struggling to work out how to access the store outside of React such as in a simple helper function. My store.ts file exports a makeStore function which is needed (including the initial state) for the next-redux-wrapper HOC.
I could access the store in a React component and pass it to my helper functions as an argument each time but that seems messy.
Is there a way to access the store direct from non React helper function modules?
It may not be preferable, but the store can be accessed from the window using a storeKey. The default key is __NEXT_REDUX_STORE__ and using it look like this:
window.__NEXT_REDUX_STORE__.getState()
Here's where that happens
The key (storeKey) can be changed in the second options parameter passed to the withRedux function parameter. For your implementation it looks like this:
export default (
initialState: any = undefined,
{ storeKey: 'whateveryouwant' } // the name on the exposed store variable
) => createStore(
rootReducer,
initialState,
composeWithDevTools(applyMiddleware()),
);
I had the same issue but found the solution.
The Readme of this lib gives the example of makeStore function like this:
const makeStore = (initialState, options) => {
return createStore(reducer, initialState);
};
You need to modify it a bit
let store;
const makeStore = (initialState, options) => {
store = createStore(reducer, initialState);
return store;
};
export {store}
Now you can import the store from wherever you want.
Worked for me with TS
let store: ReturnType<typeof configStore>
const configStore = () => configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(thunkMiddleware),
devTools: process.env.NODE_ENV !== 'production',
});
export const makeStore = () => {
store = configStore();
return store;
};
export type AppStore = ReturnType<typeof makeStore>;
export type AppState = ReturnType<typeof combinedReducer>;
export type AppThunk<ReturnType = void> = ThunkAction<ReturnType, AppState, unknown, Action>;
export type AppDispatch = ReturnType<AppStore['dispatch']>;
export const wrapper = createWrapper<AppStore>(makeStore, { debug: false });
export { store };
You can create high-order function to wrap any other function with store. Here is simple example that pass store as this argument to any other function.
function withReduxFunction(store) {
return function (connectedFunction) {
return function (...args) {
connectedFunction.call(store, ...args);
}
}
}
And usage. For example we want to provide store to this function
function doSomthingWothStore(arg1, arg2) {
console.log(this); // This will be store
console.log("arg1: " + arg1 + " arg2 " + arg2);
}
Do
const funcWithStore = withReduxFunction(store)(doSomthingWothStore);
Now you can call funcWithStore and this will be equal to store.
You can play with high-order function to make it suitable for you (i.e. pass store as first argument and so on).
Also you can take a look at useDispatch and useSelector hooks from react-redux. They also should work with any function.
You can import store module wherever it is needed and directly access the store functions like store.getState(). However, you need to subscribe to store to be notified of any change in the state.
You can create store first and then return it from makeStore()
export const store = createStore(...)
const makeStore() {
return store
}
export const wrapper = createWrapper(makeStore, { debug: true })
I'm a little bit confused with vuex store component.
How should I obtain state of another module?
I tried a different ways to get data from store and always got Observer object. What is the correct way to knock knock to observer?
If I try to get anything from this object directly, like rootState.user.someVariable then I got undefined response.
Don't have a problem getting state from components.
Edit. Add code
User module
import * as Constants from './../../constants/constants'
import * as types from '../mutation-types'
import axios from 'axios'
const state = { user: [] }
const getters = {
getUser: state => state.user
}
const actions = {
getUserAction ({commit}) {
axios({method: 'GET', 'url': Constants.API_SERVER + 'site/user'})
.then(result => {
let data = result.data
commit(types.GET_USER, {data})
}, error => {
commit(types.GET_USER, {})
console.log(error.toString())
})
}
}
const mutations = {
[types.GET_USER] (state, {data}) {
state.user = data
}
}
export default { state, getters, actions, mutations }
Mutatinos
export const GET_LANGS = 'GET_LANGS'
export const GET_USER = 'GET_USER'
Store
import Vuex from 'vuex'
import Vue from 'vue'
import user from './modules/user'
import lang from './modules/lang'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
user,
lang
}
})
Main app
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store/index'
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: { App }
})
Lang module, here is the place where I'm trying get store
import * as types from '../mutation-types'
import {axiosget} from '../../api/api'
const state = { langList: [] }
const getters = {
getLangs: state => state.langList
}
const actions = {
// this two action give me similar result
getLangsAction (context) {
axiosget('lang') // described below
},
getAnotherLangsAction (context) {
console.log(context.rootState.user) <----get Observer object
}
}
const mutations = {
[types.GET_LANGS] (state, {data}) {
state.langList = data
}
}
export default { state, getters, actions, mutations }
axiosget action, api module
import * as Constants from './../constants/constants'
import store from '../store/index'
import axios from 'axios'
export const axiosget = function (apiUrl, actionSuccess, actionError) {
console.debug(store.state.user) // <----get Observer object, previously described
// should append user token to axios url, located at store.state.user.access_token.token
axios({method: 'GET', 'url': Constants.API_URL + apiUrl
+ '?access_token=' + store.state.user.access_token.token})
.then(result => {
let data = result.data
// todo implement this
// }
}, error => {
if (actionError && actionError === 'function') {
// implement this
}
})
}
Component, that call dispatcher. If i get state via mapGetters in computed properties - there is no problems
<template>
<div>
{{user.access_token.token}}
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'ArticlesList',
computed: mapGetters({
user: 'getUser'
}),
created () {
this.$store.dispatch('getLangsAction')
this.$store.dispatch('getAnotherLangsAction')
}
}
</script>
What I'm trying to do in this code - get user access token in main site (after login) and all further manipulations with data will be produced via api host.
Let's say you want to fetch state an attribute userId from object userDetails in Vuex store module user.js.
userDetails:{
userId: 1,
username: "Anything"
}
You can access it in following way in action
authenticateUser(vuexContext, details) {
userId = vuexContext.rootState.user.userDetails.userId;
}
Note: After rootState and before file name user, add the path to the store module file if it is inside nested folders.