How to populate an array variable in pinia from a vue component at mount - vuejs3

I have a vue3 app with a pinia store. When a vue component loads it reads a json object. I want this to be fed into an array in pinia. When trying (in options API)
mounted: {
Object.keys(this.myjson).map(function (v) {
this.filters[v] = [];
});
},
// after having
computed: {
...mapWritableState(useSearchStore, ["filters"]),
},
I get an error [Vue warn]: Slot "default" invoked outside of the render function and the array in pinia stay empty.
What is the correct way to populate data in pinia from a component at mount?

Related

Dispatch actions with Redux Toolkit requires two arguments

Using Redux Toolkit, I'm trying to dispatch an action without context of event or etc., so I get the following error:
error TS2554: Expected 2 arguments, but got 1. An argument for 'action' was not provided.
With following code:
const App = () => {
const dispatch = useDispatch();
useEffect(() => {
(async () => {
const result = await fetchConfig();
dispatch(setConfig({ ConfigReducerState: result })); // ---> Error is here <---
})();
}, [dispatch]);
};
The reducer:
export const configSlice = createSlice({
name: 'config',
initialState,
reducers: {
setConfig(state, action) {
const { server, map } = action.payload;
state.server = server;
state.map = map;
},
},
});
Usually I give one parameter to action creator functions - object representing the payload, no need to refer the state. But here I can't. What am I doing wrong?
I've seen this before and every time, it was... a bug in IntelliJ/WebStorm.
See https://youtrack.jetbrains.com/issue/WEB-46527 and https://youtrack.jetbrains.com/issue/WEB-42559 - essentially, WebStorm has their own "quick TypeScript interpolation that does not use the official tsserver for type checking, but something self-cooked, that guesses types just based on things having similar names - and regularly gets things wrong.
If I understand their system correctly, you should be able to see the correct types by hovering over while holding Ctrl down.
In the end, I can't really tell you how to fix this other than switching to an IDE that does not randomly guess, but actually uses TypeScript to evaluate TypeScript types.
How did you import setConfig? I had the same issue and it turned out that by mistake I used
import setConfig from './configSlice'
instead of
import { setConfig } from './configSlice'
It was importing the default export (whole slice reducer, aliased as setConfig) instead of just this one function...

What is `app` property when access child firebase database (javascript)

This is my file that initialize firebase:
export default class {
static parent = RNFirebase.initializeApp();
static child = null;
constructor() {
child = this.parent.database('child-database-url');
}
}
In another file I use this as:
import FDBS from '../initializer';
FDBS.child.app.database().ref('orders').once("value", data => {
console.log(data);
});
And this line of code confuse me: FDBS.child.app.database().ref( actually .app.
Why I need to access this property to get data actually what I am trying to get is to be able to write code like: FDBS.child.database().ref('orders').once(...
To start with, let's fix your syntax error regarding the "static" variables in your initializer.js file. Instead of using a class for such a simple data structure, just export an object.
import RNFirebase from '#react-native-firebase/app';
import '#react-native-firebase/database';
// inits & returns the default FirebaseApp instance
const parent = RNFirebase.initializeApp(); // or RNFirebase.app() if initialized automatically
// gets a FirebaseDatabase instance that points to 'child-database-url'
const child = parent.database('child-database-url');
export default {
parent, // this is a FirebaseApp object
child // this is a FirebaseDatabase object
}
Now, as shown in the above snippet, your parent object is an instance of the FirebaseApp object and the child object is an instance of the FirebaseDatabase object.
In your code that loads in FDBS, you access FDBS.child.app (reference) which returns the FirebaseApp object associated with that instance of FirebaseDatabase - in your case this object is FDBS.parent.
As the two objects have different types, I recommend choosing to export either two FirebaseApp instances or two FirebaseDatabase instances.
Export FirebaseApp instances
Based on your question, you seem to be expecting that the child object is also a FirebaseApp object because you want to call FDBS.child.database().ref(...).
import RNFirebase from '#react-native-firebase/app';
import '#react-native-firebase/database';
const parent = RNFirebase.initializeApp(/* config */); // or RNFirebase.app()
const child = RNFirebase.initializeApp({
...parent.options, // copies everything from the default app's configuration
databaseURL: 'child-database-url' // but overwrites the value of databaseURL
});
export default {
parent, // this is a FirebaseApp object that uses the default "parent" database
child // this is a FirebaseApp object that uses the "child" database
}
You would use this as follows:
import FDBS from '../initializer';
FDBS.child.database().ref('orders').once("value", data => {
console.log(data);
});
This approach introduces a problem when you involve authentication. If a user signs into your app, they will be signed in for the default FirebaseApp instance but not the one used by FDBS.child (unless you explicitly do so). Because of this I recommend the other approach.
Export FirebaseDatabase instances (recommended)
import RNFirebase from '#react-native-firebase/app';
import '#react-native-firebase/database';
const defaultApp = RNFirebase.initializeApp(/* config */); // or RNFirebase.app()
const dbParent = defaultApp.database();
const dbChild = defaultApp.database('child-database-url');
export default {
// app: defaultApp, // (if you want to export the FirebaseApp object too)
parent: dbParent, // this is a FirebaseDatabase object that points to the default "parent" database
child: dbChild // this is a FirebaseDatabase object that points to the "child" database
}
You would use this as follows:
import FDBS from '../initializer';
FDBS.child.ref('orders').once("value", data => {
console.log(data);
});
Note: Don't forget to handle errors. I encourage using promises rather than callbacks.
Edit in response to your comment
You don't show where RNFirebase comes from, but you should be able to access your database like
let initapp = RNFirebase.initializeApp()
let db = initapp.database('url')
db.ref....
Right now you've done that in a roundabout way
child = this.parent.database(
And if you check how you define parent, it's basically like the snippet I provided above.
So you could just be a little bit more concise less circular.
--
From the official docs, https://firebase.google.com/docs/reference/js/firebase.database.Database#app
The app associated with the Database service instance.
Where app has on it the database property, among others https://firebase.google.com/docs/reference/js/firebase.app.App#database
Gets the Database service for the current app. Example
var database = app.database();
// The above is shorthand for:
// var database = firebase.database(app);

redux error on the property 'type' while using middlewares

I'm trying to integrate a logger in my redux app, using the applyMiddleware api, but when I trigger an action I got this error:
Actions may not have an undefined "type" property. Have you misspelled a constant?
This is strange because all of my action creators returns objects with this format:
{ type : ..., payload : {...}}. And more, in the console of the browser the printed object has the property 'type'.
I set up the store in this way:
const logger = store => next => action => {
console.log(action);
return next(store, action);
}
const store = createStore(
reducer,
applyMiddleware(logger));
export default store;
I got stuck.

Apollo Client and Redux setup causes infinite render loop

I'm trying to link up React Apollo with Redux so Apollo performs the queries and mutations, and the returned data is dispatched to the Redux store in order to distribute the data around the app.
I believe I'm close to getting it right, but for some reason the app goes into an infinite loop of Redux dispatches, and I can't figure out why.
See code below:
class Admin extends Component {
constructor(props) {
super(props);
}
render({
adminAllTokens
}, {}) {
return ( /* JSX */ )
);
}
}
const AllRefreshTokens = gql `
query {
allUsers {
refreshToken
email
}
}
`;
const gqlWrapper = graphql(AllRefreshTokens, {
props: ({
ownProps,
data
}) => {
ownProps.receivedAdminTokens(data.allUsers); //dispatch to Redux store
return {
...data,
gqladminAllTokens
};
}
});
function mapStateToProps(state, ownProps) {
return {
adminAllTokens: state.auth.adminAllTokens
};
}
function mapDispatchToProps(dispatch) {
return {
receivedAdminTokens: tokens => {
dispatch(adminTokensReceived(tokens));
}
};
}
const reduxWrapper = connect(mapStateToProps, mapDispatchToProps);
export default compose(reduxWrapper, gqlWrapper)(Admin);
The adminTokensReceived() action is in the reducer file:
export const adminTokensReceived = tokens => ({
type: 'ADMIN_TOKENS_RECEIVED',
tokens
});
The GraphQL query only sends one network request, but the console is showing the ADMIN_TOKENS_RECEIVED action dispatching constantly and crashes the browser.
Thanks in advance
Whenever the Apollo HOC receives new props, it causes your action to fire, which updates the store and sends new props to your Apollo HOC, which causes your action to fire...
There's a couple of different ways you could handle this. In my mind, the most straightforward would be to drop the graphql HOC and use withApollo instead. Something like:
compose(
withApollo,
connect(mapStateToProps, mapDispatchToProps)
lifecycle({
componentDidMount() {
const { client } = this.props
client.query({ query: AllRefreshTokens })
.then(({data}) => {
receivedAdminTokens(data.allUsers)
})
.catch( //any error handling logic )
}
})
)
The above uses recompose's lifecycle but you could just as easily stick the componentDidMount method inside your component.
That said, it seems a little redundant to use Redux to store the results of your GraphQL queries when Apollo already does it for you.
Apollo's default behavior is to retrieve the data from the cache first, and only make a network request if the data doesn't exist (which is also why you only saw the one network call). That means any number of components inside your app could be wrapped with the same graphql HOC, and only the first component to be rendered would trigger a request to your GraphQL endpoint -- all other components would get their data from the cache.

Firebase .on with Vue without using Vuefire

I'm trying to implement a real-time connection with Firebase's .on ref, but have no idea where to plug that in or use it in Vue. The tutorials online all use Vuefire to accomplish it, but if I just want to use the Firebase SDK, where can I activate this .on connection in my Vue project and have it work in a two-way data connection real-time?
Hmm.. It didn't seem to work.
This is what I'm using,
export default {
name: 'index',
data() {
return {
id: '1234',
meData: 'test'
}
},
mounted() {
const database = firebase.database().ref( 'rooms' + this.id );
database.on( 'value', snapshot => {
this.meData = snapshot.val();
});
}
}
I tried testing with push, it works, so the config and firebase is working, but the .on doesn't seem to work. I get no errors too so I'm having a hard time figuring out the issue. =(
At first, always the best option is to use VueFire if you need to use Vue.js and Firebase.
However, if you want to use Vue.js without Vuefire, you can set up the firebase instance in mounted section in your component. Vue component's lifecycle is not the same as the one without Vue, so you better to use lifecycle handler provided by Vue.
Vue.component("YourComponent", {
...
mounted() {
firebase.initializeApp({
apiKey: "apiKey",,
databaseURL: "https://databaseName.firebaseio.com"
});
const database = firebase.database();
database.ref('/users/100').once('value').then((snapshot) => {
// Do your business
});
...
//
// You can also set up more handlers like above...
//
},
...
});
However, if you want to use two-way binding, it is a little tough. The good point of Vuefire is its easy mixin of Vue component data structure and Firebase instance.
Without Vuefire, the code I can think up would be like this
Vue.component("YourComponent", {
...
data() {
return {
users: []
};
},
...
mounted() {
//
// Initialize Firebase SDK and get `database` to use below.
//
...
database.ref('/users').on('value', (snapshot) => {
// By using arrow function, the context of `this` here is binded
// into the current component data `users`.
this.users = snapshot.val();
});
},
...
});
In case anyone else is looking to use Firebase in Vue without Vuefire.
Do check out this video!
Vue 2 & Vuex & Firebase Tutorial - Getting It All Working Together
https://youtu.be/niPgyv53x8c

Resources