I am developing an Angular application, with angularfire2 5.0.0-rc.10. I really hope I don't mess up any terms in the following, but here we go.
I have converted Date's, to the new firestore Timestamp type. This gives me a problem when writing tests. I can only do the following:
import { firestore } from 'firebase/app';
it ('should create', () => {
firestore.Timestamp.now();
});
If I initialize firebase in my TestBed module with:
AngularFireModule.initializeApp(environment.firebase),
Otherwise I get the error:
TypeError: Cannot read property 'Timestamp' of undefined
So my questions:
Is this intended behaviour?
Are you not supposed to be able to create a firstore Timestamp data type, outside of an firebase angular project?
Why is firestore undefined when imported without the initializeApp?
Thanks so much for your help.
I resolved it below
angular version is 11.1.2
import firebase from 'firebase/app';
import 'firebase/firestore';
import Timestamp = firebase.firestore.Timestamp;
Related
Last year I spent some time learning Vue 2. I really enjoyed the framework but did not move forward with a project. I now have time for a project but I'd like to use Vue 3 with the composition API. I'll be using Firebase as the backend. I've seen conflicting techniques on whether or not to use Vuex.
For example, I'd like to store a "currentUser" object in global state that can be accessed from any component in the app. Normally, it would be done using Vuex. I'd have a getter to return the object, an async action to get the data from firebase and a mutation to set the state.
However, I've seen several Vue 3 code examples that do not use Vuex at all, instead they do something like this to get/set a currentUser in an app wherever it is needed for example in a navbar component.
composables/getUser.js
import { ref } from 'vue'
import firebase from 'firebase/app'
// refs
const user = ref(firebase.auth().currentUser)
// auth changes
firebase.auth().onAuthStateChanged(_user => {
console.log('User state change. Current user is:', _user)
user.value = _user
});
const getUser = () => {
return { user }
}
export default getUser
With this little bit of code above, I'm able to import getUser.js and access the currently logged in user using code like this. Also, the user object is now reactive:
<script>
import getUser from '../composables/getUser'
export default {
setup() {
const { user } = getUser()
return { user }
}
}
</script>
It seems I can use these little functions to get data from db directly without the need to use the Vuex pattern, which I find to be a bit more complicated.
So, my question is - if I'm starting a new Vue 3 project, is it ok to create "composable" functions to get/set data and import them into my components instead of using Vuex? Are there any downsides to this method? Or should I just stick with Vuex?
Short answer - You don't need it.
Long answer - It depends.
It depends mostly on your app and how often do you use "currentUser" data inside your components. If it's in 2 or more components, how often do you want to perform actually fetching from backend?
Once on app-init/login or every time each component mounts?
(probably once)
Does it need to be reactive? If yes - then you'll probably use centralized data pattern, your own or a library. Taken that into consideration it's probably more simple to just use Vuex.
I have several NPM codebases that use Firestore. One is client-side, one is server-side, and I am trying to refactor some code to a common dependency codebase. The server codebase uses firebase-admin as its dependency, but if I try to set objects with sentinel types (e.g. firebase.firestore.Timestamp), I incur this error:
Please ensure that the Firestore types you are using are from the same NPM package
I can avoid mixing firestore implementations by injecting the instance into my library codebase, e.g.:
import * as admin from "firebase-admin";
const libraryCode = new MyFirestoreLibrary(admin.firestore())
But, are there ways to access these sentinel types in library code?
An example of what I'm hoping to make work is here: https://github.com/okhobb/firestore-dependency-tester
I agree this is extremely silly from the firebase team. I'm in your exact sitiuation, and have shared code where I define types and objects between both client and server - sounds reasonable right?
Here's my workaround:
import * as firebase from 'firebase-admin';
import Timestamp = firebase.firestore.Timestamp;
export const now = () => {
const newTimestamp = Timestamp.fromMillis(Date.now()) as any;
const ret = JSON.parse(JSON.stringify(newTimestamp));
for (const prop of Object.getOwnPropertyNames(Timestamp.prototype).filter(prop => prop !== "constructor"))
ret[prop] = newTimestamp[prop]
return ret as Timestamp;
}
This just creates a new object and copies the properties so that the toDate, toMillis etc functions are all still there, it's just not a direct instance of timestamp, so any instanceof checks will return false.
After doing that awful hack, it seems like the check they have in place to make sure "you are importing from the same npm package" no longer works.
I'm new to all of these technologies, but as far as I understand it, you can use React Native with Redux and Firebase without react-redux-firebase. You could just use
react
react-native
redux
react-redux
react-native-firebase
Then you load data from Firebase (e.g. Firestore) and put the data in a reducer so it gets merged into the redux store.
Why do I need react-redux-firebase? What problem does it solve?
I have tried its docs, but they seem to be written for someone who is already familiar with its goals. They do not really explain, and when reading the examples, I do not understand why I specifically need react-redux-firebase instead of the setup listed above.
Firebase is on your state, listen to it an modify it, it will change your Firebase database. After the data on the database is changed the components listening will change as well.
This will create an item in the database
updateTodo: props => () => {
return firebase.update(`todos/${params.todoId}`, { done: !todo.isDone })
}
So any component listening to that node will get updated:
connect((state) => ({
todos: state.firebase.data.todos,
// profile: state.firebase.profile // load profile
}))
It solves the problem of having multiple sources of truth, your Firebase database is your only source of truth, otherwise, you change your local data and then you update the data online and then if it works nothing else but if it fails you have to update the local data again
I have a large react-redux based application in development. I'd like to add some utility functions to a js script that does not contain a react component to "connect" to. How do I access the state in react-redux without a component? Neither mapStateToProps nor mapDispatchToProps are available - do I need to export the state object from the top-level index.js file? Seems dangerous.
Suggestions welcome!
JB
Workaround way:
Import your store inside the scope of your utility functions.
Importing the store (which you would have created while setting up your app) will provide dispatch and getState methods using which you can get access to your state vars.
src/store.js
import ReduxThunk from 'redux-thunk';
import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';
import reducers from './reducers';
var middleware = [ReduxThunk];
if (process.env.NODE_ENV !== 'production') {
middleware = [...middleware, logger];
}
const createStoreWithMiddleware = applyMiddleware(...middleware)(createStore);
export default createStoreWithMiddleware(reducers);
helper.js
import store from "./store"
const { var1, var2 } = store.getState();
The phrasing of your question is just a bit odd. If you're asking about accessing the store in utility functions that aren't related to any components, then you aren't using React-Redux to do so :)
In this case, you would either import the store directly into those utility function modules, or call the functions from some scope that does have access to store capabilities (such as a thunk action creator that was dispatched from a connected component).
There's a related Redux FAQ entry on why you should generally prefer to not import the store directly.
No really graceful way to do it. Long argument list it is.
I am using momentjs and moment-range with a Typescript, so I have install typings for moment-range from npm #types, and the typing for momentjs comes with it.
import * as moment from 'moment';
import 'moment-range';
...
private tableDatePeriod: moment.Range;
but on compile I am getting this error - [ts] Module 'moment' has no exported member 'Range'.
Try this
import * as moment from 'moment';
import { default as DateRange } from 'moment-range';
let Range=new DateRange(dayFrom, dayTo);
Range.toArray('days');
let DatesArray=[];
diffDatesArray.push(moment(some_prop_from_array._d).format("YYYY-MM-DD"));
The following works for me for versions:
moment: 2.17.1
moment-range: 2.2.0
#types/moment-range: 2.0.33
The problem is that moment-range.js does not export any new entity for the range functionality, it extends moment type with range functionalities. Therefore these functionalities should be imported from moment.
import {Moment, Range, range as RangeConstructor} from "moment";
This import loads the moment-range functionalities from moment. In this example I import Range interface and range factory method (to create/construct ranges).
That should be enough, but in case you are using some type of AMD or similar dependency, the moment-range module should be loaded (required using AMD terms).
The following is the hack that works for me:
import DateRange = require("moment-range");
DateRange;
The first import includes moment-rangemodule as a dependency of the current module, therefore it is loaded as required first.
The second line does nothing, but the TypeScript compiler removes unused dependencies, so the former imported dependency must be invoked in some way in order to avoid such compiler optimization.
In reference to your question, you can now instantiate the variable:
private tableDatePeriod: Range;
And initialize:
tableDatePeriod = RangeConstructor('2016-01-09', '2016-01-10');