csfrequency / react-firebase-hooks Goto Github PK
View Code? Open in Web Editor NEWReact Hooks for Firebase.
License: Apache License 2.0
React Hooks for Firebase.
License: Apache License 2.0
Hi,
I'm using
const query = firestore.collection('cms').doc('events').collection('cmsevents');
const options =
{
idField: '_uid'
}
try {
const [values, loading, fberror] = useCollectionDataOnce<IEvent>(query, options);
console.log('values, loading, fberror', values, loading, fberror)
// Production code
return (
<div>
<Title>Your Events</Title>
{error ? (
<Alert variant="danger" onClose={() => setError(null)} dismissible>
<Alert.Heading>Error</Alert.Heading>
<p>{error}</p>
</Alert>
) : null}
{fberror && <strong>Error: {fberror}</strong>}
{loading && <span>Document: Loading...</span>}
{values && <pre>Documents: {JSON.stringify(values, null, 2)}</pre>}
<Button onClick={() => {
history.push('events/_new');
}
}>Add</Button>
</div>
);
} catch (error) {
return (<pre>{JSON.stringify(error, null, 2)}</pre>)
}
It works perfect.
But if i update my roles in firestore, i will get a exception
FirebaseError: Missing or insufficient permissions.
Getting this error is ok.
My expectation was, that this is also caught and add to error.
Unfortunately this is not the case and my side crashes.
Do you have any suggestions how to catch the firestore exception?
Many thanks!
Hi,
I've been trying the useAuthState
hook and looks like the initialising
variable is not working.
Here is the code:
export default function Login() {
const { initialising, user } = useAuthState(firebaseAuth());
const login = () => {
firebaseAuth().signInWithEmailAndPassword('[email protected]', 'test123');
};
const logout = () => { firebaseAuth().signOut(); };
if (initialising) {
return (
<div>
<Spinner marginX="auto" marginY={50} />
</div>
)
}
if (user) {
return (
<div>
<p>Current User: {user.email}</p>
<Button onClick={logout}>Log out</Button>
</div>
);
}
return (
<Button onClick={login}>Log in</Button>
)
}
The login/logout works fine, but I've confirmed that the initialising
block is never reached.
Thanks in advance,
Geraldo
Question: is there any way to paginate through firebase list using this library?
hi I am new to react and firebase. just started using react-firebase-hooks
using react-firebase-hooks i successfully got all the data in the document.
i am wondering if i could get data individually.
(i.e)
import React from "react";
import { useAuthState } from "react-firebase-hooks/auth";
import { useDocument } from "react-firebase-hooks/firestore";
import firebase from "firebase";
function Profile() {
const [user] = useAuthState(firebase.auth());
const [snapshot, loading, error] = useDocument(
user
? firebase
.firestore()
.collection("users")
.doc(user.uid)
: null
);
return (
<div className={classes.ap}>
{error && <strong>Error: {JSON.stringify(error)}</strong>}
{loading && <span>Document: Loading...</span>}
{snapshot && <span>Document: {JSON.stringify(snapshot.data())}</span>}
</div>
);
}
export default Profile;
In my component this code:
const [value, loading, error] = useCollection(firebase.firestore().collection('projects'));
makes value
an any
type object.
As a workaround i have done this:
type TValue = firebase.firestore.QuerySnapshot | undefined;
cons MyComponent:React.FC = () => {
const [value, loading, error] = useCollection(firebase.firestore().collection('projects'));
const value = v as TValue;
...
}
As you can see from the image, v
is any
.
Why is this so? Is any
the intended type for value
, or is it a bug, or is there something I need to do?
Extract from package.json
:
// ...
"firebase": "^6.3.4",
"firebaseui": "^4.1.0",
"next": "^9.0.1",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-firebase-hooks": "^2.1.0",
"react-firebaseui": "^4.0.0",
// ...
useCollectionData
returns new items in the array every time when a hook is called. This makes it impossible to perform an equality comparison on the values in the array because the values are always newly created.
Example:
const ComponentA = () => {
const [value, loading] = useCollectionData(db.collection(`myCollection`));
if (loading) return null
return <ComponentB value={value} />
}
const ComponentB = (props) => {
const firstItem = value[0]
useEffect(() => {
// effect is called always because firstItem is always different
}, [firstItem])
}
Workaround:
I've made a custom hook which stores data to a local state.
export const useColData = (query, options) => {
const [data, setData] = React.useState([]);
const [value, loading, error] = useCollection(query, options);
React.useEffect(() => {
if (!value) return;
setData(
value.docs.map((doc) => {
const docData = { ...doc.data() };
if (options.idField) {
docData[options.idField] = doc.id;
}
return docData;
})
);
}, [value, options.idField]);
return [data, loading, error];
};
Is it possible to change implementation of useCollectionData
to return always the same items in the array if the query result is not changed?
Just tried the example you provided
import { useAuthState } from 'react-firebase-hooks/auth';
const CurrentUser = () => {
const [user, initialising, error] = useAuthState(firebase.auth());
const login = () => {
firebase.auth().signInWithEmailAndPassword('[email protected]', 'password');
};
const logout = () => {
firebase.auth().signOut();
};
if (initialising) {
return (
<div>
<p>Initialising User...</p>
</div>
);
}
if (error) {
return (
<div>
<p>Error: {error}</p>
</div>
);
}
if (user) {
return (
<div>
<p>Current User: {user.email}</p>
<button onClick={logout}>Log out</button>
</div>
);
}
return <button onClick={login}>Log in</button>;
};
Same result. Uncaught error. Using v2.1.0
Still fleshing the idea out but wanted to note in case there was interest. It'd be handy for our use case to be able to apply transformations to returned object(s). Often times the data we have stored is not necessarily the data we want to display so we often wind up running the same transformations after fetch.
Our users always have a first_name
and a last_name
. Sometimes they also have a display_name
. We always want the display_name
to take precendence and run a transformation on retrieved data to do so.
We use Firebase timestamps which are really handy on the server and really not-so-handy on the client since they always need to be coerced with at least .toDate()
Currency formatting always winds up with something like .toLocaleString()
or something. I can't even remember off the top of my head and would need to look into our codebase for how we typically format.
Provide a transformations
property in options
that all data is run through. A transformation
could either be added to an object or overwrite a property of an incoming object.
For example, let's say my source object is a user:
{
first_name: 'John',
last_name: 'Smith',
created_at: firebase.firestore.Timestamp
}
With transformations
:
const [user, userLoading, userError] = useDocumentData(
myCollectionRef.users('1234')
, {
transformations: {
display_name: (data) => {
return data.display_name
? data.display_name
: `${data.first_name} ${data.last_name}`
},
created_at: (data) => {
return data.created_at.toDate().toDateString();
}
}
})
Expected output from console.log(user)
:
{
first_name: 'John',
last_name: 'Smith',
display_name: 'John Smith',
created_at: 'Wed Dec 18 2019',
}
I could see this coming in handy for us since we could store a handful of "schema" transformations and add to them with spread syntax. eg.
{
transformations: {
randomOneOffProp: (data) => data.field.toLowercase(),
...commonPeopleTransformsFromFile,
}
}
Ideally the same could be applied to collection data
Using the example provided I can't seem to get anything out of the store:
const FirestoreCollection = () => {
const { error, loading, value } = useCollection(
firebase.firestore().collection('hooks')
);
return (
<div>
<p>
{error && <strong>Error: {error}</strong>}
{loading && <span>Collection: Loading...</span>}
{value && (
<span>
Collection:{' '}
{value.docs.map(doc => (
<React.Fragment key={doc.id}>
{JSON.stringify(doc.data())},{' '}
</React.Fragment>
))}
</span>
)}
</p>
</div>
);
};
I just get the error Uncaught TypeError: Object(...) is not a function
Hi!
Use this lib for a project with mainly mobile users. In development on simulated iOS and android updates to the document I'm watching are seen immediately but on real devices there is a significant lag, but is solved by a refresh of the page.
Any ideas what I can do to solve?
makes sense: snapshot.data(); snapshot.id
doesn't: value.data(); value.id
Just food for though. I see you pushed 1.0 so I doubt you wanna make breaking changes. I can just wrap anyway
Hi.
I'm getting these:
node_modules/react-firebase-hooks/firestore/dist/firestore/useCollection.d.ts:2:29 - error TS2307: Cannot find module '../util'.
2 import { LoadingHook } from '../util';
~~~~~~~~~
node_modules/react-firebase-hooks/firestore/dist/firestore/useCollectionOnce.d.ts:2:29 - error TS2307: Cannot find module '../util'.
2 import { LoadingHook } from '../util';
~~~~~~~~~
node_modules/react-firebase-hooks/firestore/dist/firestore/useDocument.d.ts:2:29 - error TS2307: Cannot find module '../util'.
2 import { LoadingHook } from '../util';
~~~~~~~~~
node_modules/react-firebase-hooks/firestore/dist/firestore/useDocumentOnce.d.ts:2:29 - error TS2307: Cannot find module '../util'.
2 import { LoadingHook } from '../util';
~~~~~~~~~
react-firebase-hooks rocks, btw -- thanks!
slight (trivial) suggestion:
// current
export const useDocument = (
docRef?: firestore.DocumentReference | null,
// proposed
export const useDocument<T = firestore.DocumentData> = (
docRef?: firestore.DocumentReference<T> | null,
this would also apply to useCollection
, etc.
This would be helpful because firestore does indeed preserve the type all the way to the subsequent snapshot data()
value.
As a side-benefit, a typed ref
would improve the useDocumentData
API allowing you to deduce the returned data type without the explicit generic:
// current
const [data, loading, error] = useDocumentData<MyData>(ref);
// becomes (optional, if your ref happens to be typed)
const [data, loading, error] = useDocumentData(myDataRef); // myDataRef is DocumentReference<MyData>
ps: best practice would still be to validate the payload with yup
etc. but this would go a long way!
Is there any way to wait until the custom claims are loaded using ?
user.getIdTokenResult()
I'm trying to figure out how to use this.
My best attempt is copied below, although it generates an error that says:
ReferenceError: Cannot access 'snapshot' before initialization
[const GeneralTest = props => {
const { register, handleSubmit, setValue, errors, reset } = useForm();
const { action } = useStateMachine(updateAction);
const onSubit = data => {
action(data);
props.history.push("./ProposalMethod");
};
const [snapshot, loading, error] = useDocumentOnce(
firebase.firestore().collection('abs_for_codes'),
snapshot.push({
value: snapshot.data().title.replace(/( )/g, ''),
label: snapshot.data().title + ' - ABS ' + snapshot.id
}),
);
const [valuesField, setField ] = useState({
selectedOptionField: []
});
const handleMultiChangeField = selectedOption => {
setValue("field", selectedOption);
setField({ selectedOption });
};
const handleMultiChangeField = selectedOption => {
setValue("field", selectedOption);
setField({ selectedOption });
};
useEffect(() => {
register({name: "field"});
}, []);
]
Before hooks, I was able to use componentDidMount like so:
[class Form extends React.Component {
state = {
options: [],
}
async componentDidMount() {
// const fsDB = firebase.firestore(); // Don't worry about this line if it comes from your config.
let options = [];
await fsDB.collection("abs_for_codes").get().then(function (querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.id, ' => ', doc.data());
options.push({
value: doc.data().title.replace(/( )/g, ''),
label: doc.data().title + ' - ABS ' + doc.id
});
});
});
this.setState({
options
});
}]
I'm looking to figure out how to use this tool to extract data from the database and then use it to populate a select menu, like so:
<Select
className="reactSelect"
name="field"
placeholder="Select at least one"
value={valuesField.selectedOption}
options={snapshot}
onChange={handleMultiChangeField}
isMulti
ref={register}
/>
How can I use orderBy? I'm trying to to use after .where with useCollection and does not work.
const [list, loading, error] = useCollection( firebase.db.collection('songs').where('placeId', '==', props.match.params.place).orderBy('createdAt'), { snapshotListenOptions: { includeMetadataChanges: true }, } );
I really appreciate the work on this library.
I have one feature request. Is it reasonable to add a timestamp field to the return array?
So for example [value, loading, error, timestamp] = useCollection(...)
My use case is that I often use the last modified timestamp on a document to trip React caching in useEffect, useMemo, etc. However, this requires logic to look at the docs to see if any of them were modified in order to update the cache arguments to useEffect to do some processing. For most of my use cases, I could easily use the timestamp from the last time the FB onSnapshot event was triggered.
Hello there! :-)
I'm using the same code provided as example and the initialising and error states are never reached... login and logout are working fine.
Just found a related topic, but I installed the "react-firebase-hooks" packpage today so it shouldn't be happening.
Hey!
Great lib! Wondering if it would be useful to add useCollectionGroup
and useCollectionGroupData
.
Use case: querying a single document using a collectionGroup
query.
Example:
const SomeCollectionComponent = ({ someId }) => {
// useDocument cannot be used since `useDocument` expects a `DocumentReference<DocumentData>` and my query returns a `Query<DocumentData>`
[snapshots, error, loading] = useCollectionData(
firebase
.firestore()
.collectionGroup('someCollection')
.where('id', '==', someId)
)
// After rror and loading checks
const document = snapshots[0]
// do something with document
}
Proposed implementation:
useCollectionGroupData = (query) => {
const [snapshots, loading, error] = useCollectionData(query)
return [snapshots && snapshots[0], loading, error]
}
Lemme know if I can work on this!
Cheers
When using a query containing the 'where date' clause as below, the data loads correctly but the component and its children are constantly reloaded. Removing the .where('date', '>', Firebase.firestore.Timestamp.now())
stops this happening. I migrated to this project from another and this logic worked correctly there.
Is there anything I'm doing wrong?
Thanks
`
const withEvents = Component => props => {
const provider = useContext(CalProvider);
const _class = useContext(ClassProvider);
console.log('withEvents loading');
const [values, loading, error] = useCollectionData(
Firebase.firestore()
.collection(`providers/${provider.id}/events`)
.where('classId', '==', _class.id)
.orderBy('date', 'asc')
.limit(4),{idField:'id'}
);
if (error) return <Error error={error} />;
if (loading) return <CircularProgress />;
if (values.length === 0) return <NoEvents />;
return (
<EventsProvider.Provider value={values}>
<Component>{props.children}</Component>
</EventsProvider.Provider>
);
};`
Are there are any plans to provide an option to use useLayoutEffect
instead of useLayout
?
If on application load useAuthState
is leveraged to determine whether to render a sign in screen or user dashboard, then the sign in screen is painted before the component receives the updated state. That causes a quick flash of the sign in screen.
This causes PublicRoutes
to flash:
const Routes = () => {
const { user } = useAuthState()
return (
user
? <AuthenticatedRoutes /> // <-- user dashboard is here
: <PublicRoutes /> // <-- sign in screen is here
)
}
Here is a proposed change to useAuthState.ts
:
import { auth, User } from 'firebase';
import { useEffect, useLayoutEffect } from 'react';
import useLoadingValue from '../util/useLoadingValue';
export type AuthStateHook = {
user?: firebase.User;
initialising: boolean;
};
export default (auth: auth.Auth, delayPaint: boolean): AuthStateHook => {
const { loading, setValue, value } = useLoadingValue<User>(auth.currentUser);
const effect = delayPaint ? useEffect : useEffect;
effect(
() => {
const listener = auth.onAuthStateChanged(setValue);
return () => {
listener();
};
},
[auth]
);
return {
initialising: loading,
user: value,
};
};
Hi, I have some data structured something like the following:
Normally, I might break this up into separate components that each have their own hook, but I am using a library that accepts the data in hierarchical form. Is there a way I can query the whole structure at once? Alternatively, do people have best practices for structuring data like this so it can be queried in parts and then assembled in an efficient way (for reading, say)?
Playing around with it now, may update with work in progress as I go.
For Firestore collections and docs, it would be nice if each of the ...Data
hooks would automatically add the idField
(if provided) as a key/value to the <T>
generic.
For example, the useDocumentData
hook would return something like T & { idField: string }
instead of just T
. In this case, idField
should be represented by the actual string value entered into options.idField
.
Does this make sense? I feel like it should be trivial to do something like this, but couldn't quite get it to work myself. I'd be happy to make a pull request if anyone has some extra insight.
Thanks!
Hello everyone,
just wondering if this repo is not just a duplicate (with few functions more) of https://github.com/FirebaseExtended/reactfire which also include hook
Thanks you very much
Thanks for this library I guess this issue is related with Firebase/auth
itself and not the hook but this is the journey:
user.emailVerified: false
on the topuser.emailVerified: false
remainsuser
entity user.emailVerified -> true
user.emailVerified
changes triggers a component re-render
user.emailVerified: true
In the main example in the readme, CurrentUser
creates new login
and logout
functions on every render. Is this necessary somehow, due to the way React hooks work, or can these functions be safely moved outside?
I would like to see some mutation support for making changes in firebase not just reading data. I would look to apollo mutation hooks for inspiration. Ideas that I have in mind are along these lines:
function useDocumentUpdate<T>(docRef: firestore.DocumentReference): [(data: T) => void, boolean, Error | undefined] {
const [mutating, setMutating] = useState(false)
const [error, setError] = useState<Error | undefined>(undefined)
const updateDoc = (data: T) => {
setMutating(true)
docRef.update(data).catch(e => setError(e)).finally(() => setMutating(false))
}
return [updateDoc, mutating, error]
}
It looks like the loading utility hook types the value
property as void
. This makes it difficult to work around potential edge cases in the code:
let [ user, userIsLoading, userError ] = useAuthState(firebase.auth());
if (userIsLoading) {
return null;
}
// do something with user ...
user.someProperty; // <- errors with "someProperty doesn't exist on type void | User"
The problem here is that, because user
is typed as possibly being void
(which is different from undefined
), I can't even do something like user!.someProperty
to assure TS that the variable will have a value.
I think the fix here is to switch to undefined
as the fallback type.
import { useCollection } from 'react-firebase-hooks/firestore';
Results in this error: cannot find module ../util
Called by .../node_modules/react-firebase-hooks/firestore/dist/firestore/useCollection.d.ts
Version: 2.0.0
After changing the ref in useDocumentData I first get loading: false, value: undefined.
It seems that the isEqualRef is called afterward.
When the ref change, loading should immediately set to true.
I was wondering if there was a way to use this library to do async requests in multiple hooks. In my use case, I'm calling a document that has the id for another document and I need this id to get the other document.
const [selectionData, loadingS] = useDocumentData(firestore.doc(`selections/${selection}`), { idField: 'id' })
const [friendData, loadingF] = useDocumentData(firestore.doc(`friends/${selectionData.id}`), { idField: 'id' })
Before I was using a custom hook with an async function but I was wondering there was a way to do it with your library.
To give a bit of context on what I'm trying to achieve, this code do the trick for now:
function useOccasion() {
const [occasionData, setOccasionData] = useState(null)
const [friend, setFriend] = useState(null)
let { occasion } = useParams()
useEffect(() => {
const unsubscribe = firestore.collection('occasions').doc(occasion)
.onSnapshot(async eventData => {
setOccasionData({id: eventData.id, ...eventData.data()})
let friendData = await firestore.collection("friends").doc(eventData.data().friend).get();
setFriend({id: friendData.id, ...friendData.data()});
})
return () => unsubscribe()
}, [occasion])
return [occasionData, friend]
}
So if there's a way to reproduce this with these hooks that would be amazing.
Example:
const [authUser, authLoading, authError] = useAuthState(firebase.auth());
const [user, userLoading, userError] = useDocument(firebase.firestore().doc(`users/${authUser.uid}`));
I can't put useDocument
in a if (authUser)
because React breaks with: Rendered more hooks than during the previous render.
I'm getting TypeError: v1.isEqual is not a function
when I use the useDocument
hook
const profileRef = firebase
.firestore()
.collection('users')
.doc(user.uid)
const { error, loading, value } = useDocument(profileRef)
"react": "16.8.3",
"react-firebase-hooks": "^1.1.0",
"react-native": "0.59.1",
"react-native-firebase": "^5.2.3",
Any ideas?
I have a collection that requires an authenticated login to access. When I first view the collection in an un-authenticated state I of course do not get any content. If I subsequently authenticate, I expect the collection to populate with contents so useCollection will 'refresh'. However, this does not occur.
Is there a technique I can use to force useCollection to refresh content?
I couldn't find anything about refreshing data for a document that is loaded using useDocumentDataOnce
. My app will have a refresh button or a pull-to-refresh gesture.
I tried using a dummy local state to force the re-render but it doesn't work since the document refs are the same across renders.
const [refreshCount, setRefreshCount] = useState(0);
const refresh = () => setRefreshCount(refreshCount + 1);
Is this possible to implement this behaviour?
Any chance it might get implemented? I don't understand it is not in here yet. Am I the first to ask?
I have found the collectionData() from rxfire to be super useful.
Currently, your hooks return a snapshot. While I don't find that very useful others might. So what if we added a new useCollectionData(query, idField='id') to the api.
Here is an example of how I wrap the useCollection from this library.
export const useCollectionData = (query, idField = 'id') => {
const { error, loading, value } = useCollection(query)
const docs = []
if (!loading) {
value.forEach(snap => {
docs.push({
...snap.data(),
[idField]: snap.id,
})
})
}
return [docs, loading, error]
}
There are two things to notice. The first is that I return a collection of documents NOT a snapshot. The second is that I return an array just like useState() from React. I find this very helpful when using multiple useCollections() with a Component.
The same feature could be added to the useDocument() hooks as well.
Unless I'm missing something, besides listening to the firebase DB, how can we send or update data to it with some custom hook?
Seems like a common flow I see for defining admin users is to have an admin collection, and then you can check the authenticated user against that collection to make a determination.
Since hooks can't show conditionally, the syntax for doing this seems to be along the lines of:
const { initializing, user } = useAuthState(auth);
const { loading, error, value } = useDocument(db.doc(`admins/${ user && user.email }`));
...
const isAdmin = !!value.exists;
In this case, we begin by querying via useDocument
for a document we know won't work (admins/
), but it of course works fine when user.email
is available.
Is there a better way of doing this with hooks and firebase?
Otherwise you get weird logic when value is undefined but neither error nor loading is true
When I use useAuthState
with signInWithPopup
and close the popup without authenticating, the error state is not reached.
After a second these two errors appear in the console:
Uncaught: {code: "auth/popup-closed-by-user", message: "The popup has been closed by the user before finalizing the operation."}
Uncaught Error: The error you provided does not contain a stack trace.
I was expecting this error to cause useAuthState to reach the error state. Is this behavior expected?
The following code dropped into the CreateReactApp boilerplate will reproduce this error. In fact, all errors seem to cause the aforementioned result.
import React from 'react'
import * as firebase from 'firebase/app'
import 'firebase/auth'
import { useAuthState } from 'react-firebase-hooks/auth'
const firebaseConfig = {
// copied from firebase console
}
firebase.initializeApp(firebaseConfig)
const provider = new firebase.auth.GoogleAuthProvider()
const login = () => {
firebase.auth().signInWithPopup(provider)
}
export const logout = () => {
firebase.auth().signOut()
}
export const App = () => {
const [user, initialising, error] = useAuthState(
firebase.auth(),
)
if (initialising) {
return (
<div>
<p>Initialising User...</p>
</div>
)
}
if (error) {
return (
<div>
<p>Error: {error}</p>
</div>
)
}
if (user) {
return (
<div>
<p>Current User: {user.email}</p>
<button onClick={logout}>Log out</button>
</div>
)
}
return <button onClick={login}>Log in</button>
}
My package versions:
{
"firebase": "^6.6.2",
"react": "^16.9.0",
"react-firebase-hooks": "^2.1.0",
}
Thanks for the great library!
Is there a simple way to run a function every time a new snapshot is loaded by the client? I need to run a simple function that makes some changes to the data gotten from firestore, and then sets a useState
value. Currently, you can only use the variable provided when you initialise a useCollection
hook, meaning it is hard to format the data first before using the variable in JSX.
Could be useful I think?
Consider this example:
Categories are stored in firestore. I need to display checkboxes to select these categories, so I need to store the checked state. My approach results in an infinite loop:
Inside my component function:
const [categories] = useCollectionDataOnce(
firestore.collection('categories'),
{idField: 'id'},
);
const [categoriesBoxesValues, setCategoriesBoxesValues] = useState([]);
useEffect(() => {
if (!categories) {
return;
}
const boxes = categories
.map(c => ({
isChecked: false,
...c,
}))
// fixme: causes infinite loop
// setCategoriesBoxesValues(boxes);
}, [categories]);
Seems to be a common use case, namely to enhance a value fetched from firestore. How to solve this issue?
Thanks to #10, we are now able to do:
const { initialising, user } = useAuthState(auth);
const { loading, error, value } = useDocumentOnce(
user ? db.doc(`users/${user.email}`) : null
);
The problem is that if the user exists then a document reference is sent but useDocumentOnce
returns { loading: false, error: undefined, value: undefined }
. I was under the assumption that once loading is false, the value should be the DocumentSnapshot. It looks like this was caused by 01e8616 because calling setValue(undefined)
ends up setting the loading value to false.
I'm not sure if the best fix is to change the useLoadingValue
's reducer to check the value before setting loading to false or if instead it shouldn't call setValue(undefined)
if the value is already undefined.
When I use useCollection and useDocumentOnce together in one function component I periodically get index.js:1375 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
warnings.
Here is one of the components that throw that warning:
const Channels = ({user, feedId}) => {
const [
userValue,
userLoading,
userError,
] = useDocumentOnce(firebase.firestore().doc('users/' + user.email), {
snapshotListenOptions: {includeMetadataChanges: true},
});
const [
value,
loading,
error,
] = useCollection (
firebase
.firestore ()
.collection ('channels')
.where ('feedId', '==', feedId),
{
snapshotListenOptions: {includeMetadataChanges: true},
}
);
return (
<div className="channels">
<h1>Channels</h1>
{error && <strong>Error: {JSON.stringify (error)}</strong>}
{loading && <div>Loading Channels...</div>}
{value && userValue &&
<div>
{value.docs
.sort ((a, b) => {
return a.id > b.id ? 1 : -1;
})
.filter(doc => userValue.data().channels.includes(doc.id))
.map (doc => (
<React.Fragment key={doc.id}>
<div>
<button onClick={() => navigate ('/messages/' + doc.id)}>
{capitalize (doc.id)}
</button>
</div>
</React.Fragment>
))}
</div>}
</div>
);
};
Here is the parent component:
const App = () => {
const [user, loading, error] = useAuthState(firebase.auth());
const logout = () => firebase.auth().signOut();
return (
<div className="collaboracast">
<header className="collaboracast-header">
<h3><Link to="/">Don-Nan</Link></h3>
{user && <nav><span>{user.email}</span><button onClick={logout}>logout</button></nav>}
</header>
<main>
{!loading && <Router className="app-router">
{user && <Feeds path="/feeds" />}
{user && <Channels path="/channels/:feedId" user={user} />}
{user && <Messages path="/messages/:channelId" user={user} />}
<Login default path="/" user={user} />
</Router>}
{loading && <div>loading...</div>}
</main>
</div>
);
}
I don't think the useDocumentOnce returns a cleanup function.
In the following code, you can see that the second useCollection
requires data from the first, the organisation id. How can I chain these requests together so that the second request does not give an error, but instead waits for the first request to complete and then continue with the seconds request?
Thanks
const [organisation, loadingOrganisation, errorOrganisation] = useCollection(
firebase.firestore().collection('organisations').where("members", "array-contains", user.uid),
{
snapshotListenOptions: { includeMetadataChanges: true },
}
);
const [projects, loadingProjects, errorProjects] = useCollection(
firebase.firestore().collection('organisations').doc(organisation[0].id).collection("projects"),
{
snapshotListenOptions: { includeMetadataChanges: true },
}
);
What is the currently recommended way to fetch references from within a loaded document snapshot?
Could we add an option to automatically hydrate child references into a snapshot or data object?
Hi,
Is there away to get the provider access token? Since we can only get it right after sign in and I cannot find any documentation on how to get it with our auth hooks.
Thanks,
H
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.