I want to use Meteor.userId() inside of a viewmodel using Mobx for state management.
i.e
#observable isLoggedIn = Boolean(Meteor.userId());
The issue is, I receive this error when I attempt to do this
"Error running template:
`Error: Meteor.userId can only be invoked in method calls or publications."`
I don't believe createContainer is applicable here as it's designed for React components and this is just a standard es6 JS class.
I probably could use createContainer on my main App component and just set the loggedIn observable in an ApplicationModel or something of that sort. But that just feels hacky.
Any ideas or solutions would be greatly appreciated!
Thanks!
Attempt to wrap the entire Meteo class in an persistent observable array:
import {observable, toJS} from 'mobx';
import {persist} from 'mobx-persist';
#persist #observable _meteo = Meteo
You can then call the state when required by the component:
const {_meteo } = props.store
_meteo.userId()
..else review the toJS() data!
Related
I am currently working on a personal project in which I use both Vue 3 (with the composition api) and Firebase. I have noticed that Firebase makes frequent use of the observer pattern, but this has caused some confusion for me.
For example, the suggested way of getting the current authenticated user is using the onAuthStateChanged observer. However, say I implement this observer in a component and I now have a child component that wants to take the current user object as a prop, I have written something like this:
import { getAuth, onAuthStateChanged } from "firebase/auth";
import { ref } from "vue"
const curUser = ref()
const auth = getAuth();
onAuthStateChanged(auth, (user) => {
if (user) {
curUser.value = user
} else {
curUser.value = null
}
});
Now this works (somewhat) but I wonder if this is the wrong way to approach this. The issue is that the value curUser is undefined until onAuthStateChanged is called. This means that if curUser is passed as a prop to a child component the child has to be able to deal with it being undefined.
Is this approach correct or does this qualify as code horror? I have encountered this issue many times, another example where this exact same issue plays is with the onValue observer
i trying to get the data from my database, in componentWillMount(), it works fine with this :
var userData = null
firebase.database().ref('/users/' + user.uid).once('value').then(function(snapshot) {
userData = snapshot.val()
console.log(userData)
});
But it only works in the method only, i tried to asign the value to a variable but i can't get it outside even with this.setstate.
I am really lost it looks easy but i don't know how ...
Thanks for help.
once() is asynchronous and returns immediately with a promise. The promise does not block your code when you attach a then callback to it. userData won't be populated in the callback from the promise until after the database query completes, and you have no guarantee when that will be. If your code tries to access userData before it's finally populated, it will still have its original null value.
Well, what's happening here is,
your firebase method is taking a time to get data and because everything is asynchronous here, javascript will not wait until your firebase method is executed.
Immediate next line of firebase.database().... will be executed before this completes.
So you might need to set your data into state using setState or you can use a class variable instead of a local variable.
do this,
constructor(props){
super(props);
this.state={
data:null //either do this
}
this.localData=null; // or this
}
firebase.database().ref('/users/' + user.uid).once('value').then(function(snapshot) {
this.setState({data:snapshot.val()});
this.localData = snapshot.val();
console.log(this.localData)
});
So, I am passing store thru ApolloProvider
<ApolloProvider store={store} client={apolloClient}>
Now, ApolloProvider is putting it, the store, in client. But its putting the store object, not the actual reducer object. So, I am getting the following, which seems odd to me..
client
---> store
-----------> getState
-----------> dispatch
but no "state"? I mean, sure if I would call getState(), but that seems quite different from when I usually do redux without Apollo. I get my "state tree"... here, I am getting it...
What is the "normal" or "best practices" when using redux w/ graphql?
It seems excessive to access a state prop like so:
if (this.props.client.state.getState().whatever.foo)
Use queries to local state and React Hooks like:
import gql from 'graphql-tag';
import { useQuery } from '#apollo/react-hooks';
//...
export default () => {
const { data } = useQuery(gql('query GetTableFilter { selectedMall #client }'));
// ... do something with data.selectedMall
I have this simple saga:
export function* priceComparisonSaga() {
yield takeEvery(RECORD_PRICE, priceComparison);
}
But whenever I dispatch the event, it is never called. What's going on?
It turns out the action in question had an extra "type" property.
When using the shortcut to create actions like this,
export const addBalance = makeActionCreator(ADD_BALANCE,"balance","type");
This action won't work, because the second type property overwrites "ADD_BALANCE". Instead, this works:
export const addBalance = makeActionCreator(ADD_BALANCE,"balance","balancetype");
I have 2 reducers that are combined in a Root Reducer, and used in a store.
First reducer 'AllTracksReducer" is supposed to return an object and the second 'FavoritesReducer' an array.
When I create a container component and a mapStateToProps method in connect, for some reason the returned state of the store is an object with 2 reducer objects which hold data, and not just an object containing correposding data, as expected.
function mapStateToProps(state) {
debugger:
console.dir(state)
//state shows as an object with 2 properties, AllTracksReducer and FavoritesReducer.
return {
data: state.AllTracksReducer.data,
isLoading: state.AllTracksReducer.isLoading
}
}
export default connect(mapStateToProps)(AllTracksContainer);
so, in mapStateToProps, to get to the right state property, i have to say
state.AllTracksReducer.data... But I was expecting the data to be available directly on the state object?
Yep, this is a common semi-mistake. It's because you're using likely using ES6 object literal shorthand syntax to create the object you pass to combineReducers, so the names of the imported variables are also being used to define the state slice names.
This issue is explained in the Redux docs, at Structuring Reducers - Using combineReducers.
Create some selectors that receive the whole state (or the reducer-specific state) and use it in your mapStateToProps function. Indeed the name you define when you combineReducers will be the topmost state keys, so your selectors should take that into account:
const getTracks = (state) => state.allTracks.data
const isLoading = state => state.allTracks.isLoading
This assumes you combine your reducers with allTracks as they key like here:
combineReducers({
allTracks: allTracksReducer
})
And then you can use those selectors in your mapper, like
const mapStateToProps = state => ({
isLoading: isLoading(state),
tracks: getTracks(state)
})
There's a delicate link between your combineReducers call and your selectors. If you change the state key name you'll have to update your selectors accordingly.
It helps me to think of action creators as "setters" and selectors as "getters", with the reducer function being simply the persistence part. You call your setters (dispatching action creators) when you want to modify your state, and use your selectors as shown to get the current state and pass it as props to your components.
Well, that's how it supposed to work. When you're using combineReducers, you're literally mapping the name of a reducer to the reducer function.
If it bothers you, I would suggest a little syntactical magic if you're using es2016 (though it seems you're not) like so:
function mapStateToProps(state) {
const { data, isLoading } = state.allTracksReducer;
return {
data: data,
isLoading: isLoading
}
}
export default connect(mapStateToProps)(AllTracksContainer);
Remember, state is the one source of truth that possesses all your reducers.