Skip to content

Commit 7174ba3

Browse files
most of the hooks work now
need to add __user parsing
1 parent 7cd5721 commit 7174ba3

File tree

10 files changed

+213
-118
lines changed

10 files changed

+213
-118
lines changed

docs/firestore.md

Lines changed: 167 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,134 +1,191 @@
11
# Write
22

3+
Writing to the Firestore is simple too! All you need to do is import a hook that you want to use and initialize it with a string pointing to the collection you'll do the operation on.
4+
You'll always get an array of:
5+
- `loading` state, that indicates if the process is underway. Useful for disabling a button after submission or showing a spinner.
6+
- `error` which by default is `null`, but when there is a problem with be populated with an error message created by firebase
7+
- `function` that does the action that you requested, by calling chosen hook
8+
9+
All of the hooks take `collection` string as a parameter. Have a look at the examples below for more in detail information about that, and occasional extra parameters.
10+
311
All of the mutations get timestamps attached to them by default so you don't have to worry about them
412

5-
## Set
13+
Also all of the mutation hooks support passing in a string of `__user` to indicate that you want to replace it with currently logged in user id. [Read more about how that works here](./other.md)
14+
15+
## `useSet`
16+
17+
Use when you have an id of thing you want to change or if you want to create an item with given id.
18+
19+
`useSet` takes two arguments. Besides, as always, a `collection` string, it also takes an optional `merge` boolean (default `false`) that specifies if you want to keep previous values or overwrite the whole document with passed in object.
20+
21+
The `setFunction` it returns takes two arguments:
22+
- `uid` of the document you want to set
23+
- `data` object you want to set it to
24+
25+
### Example
626

727
```jsx
8-
// Initialize the hook with parameters
9-
// first is operation, which is a type of change you want to do on the Firestore
10-
// second is a name of the collection in Firestore you want to change
11-
// then there is an object for all of the options - always consult docs if you want to use them
12-
// as they change for different operations, though if you don't pass them they all have defaults
13-
14-
// pro tip - its helpful to read the hook like this:
15-
// const setCity = useWriteFS('set', {/* document in */} 'city', {
16-
17-
const setCity = useWriteFS('set', 'city', {
18-
merge: true, // default false
19-
});
20-
21-
// Example in a submit action:
22-
// Function needs to be async as the setCity returns a promise
23-
handleSubmit = async () => {
24-
// we need a try catch block in this async function as writing to db is done over the network,
25-
// and stuff can always go wrong
26-
try {
27-
// need to await the operation to resolve successfully
28-
// function doesn't return anything so no need to capture the outcome
29-
await setCity({data: 'that', you: 'want', to: 'save'}, 'uidOfTheDocYouWantToChangeOrCreate')
30-
// after its done you can call any other function like redirect to other path:
31-
props.history.push('/')
32-
} catch (e) {
33-
// handle the error. Might have been caused by collection not existing for example
34-
}
35-
}
28+
import React, { useState } from 'react';
29+
import { useSet } from 'firebase-hooks-react';
30+
31+
const App = () => {
32+
// we need to point the hook to the collection with the parameter string
33+
const [loading, error, setName] = useSet('names', {/* optional merge boolean */} true);
34+
const [name, setNameField] = useState('')
35+
36+
const onSubmit = (e) => {
37+
e.preventDefault();
38+
// then we can use it wherever we want, like in this submit function
39+
// that sends an object to the database with key of name and value of name (thats in the state)
40+
setName('testing', { name });
41+
};
42+
43+
return (
44+
<div className='App'>
45+
<form onSubmit={onSubmit}>
46+
<input type='text' value={name} onChange={e => setNameField(e.target.value)} />
47+
{/* useful thing is using loading boolean for disabling the button */}
48+
<input type='submit' value='Change your name' disabled={loading} />
49+
{/* you should probably do some more error handling than this, but its quick and dirty and does the work here */}
50+
{error && JSON.stringify(error)}
51+
</form>
52+
</div>
53+
);
54+
};
55+
56+
export default App;
3657
```
3758

38-
## Add
59+
## `useAdd`
60+
61+
Use when you don't want to think about what id you want to give something, you just want to add a new doc to the collection. Only takes a `collection` string.
62+
63+
The `addFunction` that the hook returns takes one argument:
64+
- `data` object containing the data you want to add.
65+
66+
### Example
3967

4068
```jsx
41-
// same process as with set, so for details have a look above
42-
// same pro-tip as above - its useful to read it like this:
43-
// const setCity = useWriteFS('add', {/* document to */} 'city')
44-
45-
// This time there are no options as we let firestore figure out the id
46-
const addCity = useWriteFS('add', 'city');
47-
48-
// Example in a submit action:
49-
// Function needs to be async as the addCity returns a promise
50-
handleSubmit = async () => {
51-
try {
52-
// need to await the operation to resolve successfully
53-
// function doesn't return anything so no need to capture the outcome
54-
await addCity({data: 'that', you: 'want', to: 'save'})
55-
// after its done you can call any other function like redirect to other path:
56-
props.history.push('/')
57-
} catch (e) {
58-
// handle the error. Might have been caused by collection not existing for example
59-
}
60-
}
69+
import React, { useState } from 'react';
70+
import { useAdd } from 'firebase-hooks-react';
71+
72+
const App = () => {
73+
// we need to point the hook to the collection with the parameter string
74+
const [loading, error, addName] = useAdd('names');
75+
const [name, setName] = useState('')
76+
77+
const onSubmit = (e) => {
78+
e.preventDefault();
79+
// then we can use it wherever we want
80+
addName({ name });
81+
};
82+
83+
return (
84+
<div className='App'>
85+
<form onSubmit={onSubmit}>
86+
<input type='text' value={name} onChange={e => setName(e.target.value)} />
87+
{/* useful thing is using loading boolean for disabling the button */}
88+
<input type='submit' value='Add new name' disabled={loading} />
89+
{error && JSON.stringify(error)}
90+
</form>
91+
</div>
92+
);
93+
};
94+
95+
export default App;
6196
```
6297

63-
## Update
98+
## `useUpdate`
99+
100+
Useful if you have a document that you know the id of and you want to update one field in it. Pretty much the same as using the `useSet` hook with merge set to true. Takes only a `collection` string.
101+
102+
The `updateFunction`, that the hook returns, takes two arguments:
103+
- `uid` of the document you want to update
104+
- `data` object with fields that you want to update in a document
64105

65106
```jsx
66-
// Very similar structure to Set function, the difference is only in the string that you have to pass,
67-
// and that there are no extra options to pass
68-
// a reading pro-tip again:
69-
// const setCity = useWriteFS('update', {/* document in */} 'city')
70-
const updateCity = useWriteFS('update', 'city');
71-
72-
// Example in a submit action:
73-
// Function needs to be async as the updateCity returns a promise
74-
handleSubmit = async () => {
75-
try {
76-
// we need to know what document you want to update - by passing its id as first arg
77-
// second parameter is an object of existing values you want to update
78-
// consult with these docs on what you can actually do with that as there are cool things like increase by one
79-
// https://firebase.google.com/docs/firestore/manage-data/add-data#update-data
80-
await updateCity({data: 'that', you: 'want', to: 'save'}, 'uidOfTheDocYouWantToChangeOrCreate')
81-
// after its done you can call any other function like redirect to other path:
82-
props.history.push('/')
83-
} catch (e) {
84-
// handle the error. Might have been caused by collection not existing for example
85-
}
86-
}
107+
import React, { useState } from 'react';
108+
import { useUpdate } from 'firebase-hooks-react';
109+
110+
const App = () => {
111+
// we need to point the hook to the collection with the parameter string
112+
const [loading, error, updateName] = useUpdate('names');
113+
const [name, setName] = useState('')
114+
115+
const onSubmit = (e) => {
116+
e.preventDefault();
117+
// then we can use it wherever we want
118+
updateName('testing', { name });
119+
};
120+
121+
return (
122+
<div className='App'>
123+
<form onSubmit={onSubmit}>
124+
<input type='text' value={name} onChange={e => setName(e.target.value)} />
125+
{/* useful thing is using loading boolean for disabling the button */}
126+
<input type='submit' value='Change your name' disabled={loading} />
127+
{error && JSON.stringify(error)}
128+
</form>
129+
</div>
130+
);
131+
};
132+
133+
export default App;
87134
```
88135

89-
## Delete
136+
## `useDelete`
137+
138+
Simply deletes a document in the firebase, based on the id that you give it. Takes a `collection` string as always.
139+
140+
The `deleteFunction`, that the hook returns, takes one argument:
141+
- `uid` of the document you want to delete
90142

91143
```jsx
92-
// You might get the theme that these hooks are meant to look very similar and no changes here
93-
// one thing you have to keep in mind that deleting a document doesnt delete its children,
94-
// you can read about it here: https://firebase.google.com/docs/firestore/manage-data/delete-data#collections
95-
const deleteCity = useWriteFS('delete', {/*document in*/} 'city');
96-
97-
// Example in a submit action:
98-
// Function needs to be async as the updateCity returns a promise
99-
handleSubmit = async () => {
100-
try {
101-
// we need to know what document you want to delete - we do that by passing its id as first arg
102-
// It doesnt return anything
103-
await deleteCity('uidOfTheDocYouWantToChangeOrCreate')
104-
// after its done you can call any other function like redirect to other path:
105-
props.history.push('/')
106-
} catch (e) {
107-
// handle the error. Might have been caused by collection not existing for example
108-
}
109-
}
144+
import React from 'react';
145+
import { useDelete } from 'firebase-hooks-react';
146+
147+
const App = () => {
148+
// we need to point the hook to the collection with the parameter string
149+
const [loading, error, deleteName] = useDelete('names');
150+
151+
const handleClick = () => {
152+
// then we can use it wherever we want
153+
deleteName('testing');
154+
};
155+
156+
return (
157+
<button value='Delete some name' onClick={handleClick} />
158+
);
159+
};
160+
161+
export default App;
110162
```
111163

112-
## Delete a field
164+
## `useDeleteFields`
165+
166+
Only deletes specified fields from a chosen document
167+
168+
The `deleteFieldsFunction`, that the hook returns, takes two arguments:
169+
- `uid` of the document you want to update
170+
- `fields` which is an array of strings of fields that you want to delete in a document
113171

114172
```jsx
115-
// probably the least useful but still here
116-
// similar to delete action, just accepts an extra argument which is an array of fields to delete
117-
const deleteFieldInCity = useWriteFS('deleteField', {/*in a document in the*/} 'city');
118-
119-
// Example in a submit action:
120-
// Function needs to be async as the deleteFieldInCity returns a promise
121-
handleSubmit = async () => {
122-
try {
123-
// we need to know in what document you want to delete passed fields - we do that by passing its id as first arg
124-
// then we need to know what fields you want to delete, pass them as an array of strings
125-
// It doesn't return anything
126-
await setCity('uidOfTheDocYouWantToChangeOrCreate', ['capital', 'population'])
127-
// after its done you can call any other function like redirect to other path:
128-
props.history.push('/')
129-
} catch (e) {
130-
// handle the error. Might have been caused by collection not existing for example
131-
}
132-
}
173+
import React from 'react';
174+
import { useDeleteFields } from 'firebase-hooks-react';
175+
176+
const App = () => {
177+
// we need to point the hook to the collection with the parameter string
178+
const [loading, error, deleteFieldsInName] = useDelete('names');
179+
180+
const handleClick = () => {
181+
// then we can use it wherever we want
182+
deleteFieldsInName('testing', ['name']);
183+
};
184+
185+
return (
186+
<button value='Delete some fields in name' onClick={handleClick} />
187+
);
188+
};
133189

190+
export default App;
134191
```

docs/other.md

Whitespace-only changes.

docs/storage.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Storage
2+
3+
## brain-dump
4+
5+
- Add button that takes care of the whole image upload
6+
- div that supports drag and drop
7+
- note that someone should make them accessible like this: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Using_file_inputs
8+
9+
## flow
10+
11+
```js
12+
return [loading, error, {
13+
spreadToInput, // object to spread on the input, has type, onChange
14+
spreadToSubmit, // object to spread on submit button to submit added file, disabled until file is added
15+
uploadFunction, // simple function thats a part of the spreadToSubmit that purely uploads the files, useful when not wanting to add a submit button
16+
progress, // an object with status of whats happening, read here
17+
}] = useStorage(
18+
'path',
19+
{ // all of these are optional
20+
accept: ['.jpg', 'image/*'], // and all the other types - more info [here](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers)
21+
capture: 'accept' | 'user' | 'environment',
22+
multiple: true | false,
23+
metadata: {
24+
// all of the metadata that the user might want to attach to the file, here are docs in FB https://firebase.google.com/docs/storage/web/upload-files#add_file_metadata
25+
}
26+
}
27+
)
28+
```

src/firestore/read/useReadFS.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { useQuery } from './useQuery';
1313
import { useReadCollection } from './useReadCollection';
1414
import { useReadDoc } from './useReadDoc';
1515

16-
export const useReadFS = <QueryType extends QueryTypes>(
16+
export const useRead = <QueryType extends QueryTypes>(
1717
query: QueryType,
1818
doc?: InferDocType<QueryType>,
1919
// Todo this needs to be made type-safe with `inferReturnType`
@@ -23,8 +23,7 @@ export const useReadFS = <QueryType extends QueryTypes>(
2323
handleError(firestore); // handle if not imported
2424

2525
// Checking if query has user in it and replacing it if needed
26-
const { user } = useR();
27-
const withUserQuery = handleUser(query, user) as QueryType; // not sure if that actually fixed it
26+
const withUserQuery = handleUser(query) as QueryType; // not sure if that actually fixed it
2827

2928
// There are 3 parts to this hook:
3029
// - collection string - useReadCollection => array of document objects

src/firestore/write/useAdd.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useState } from 'react';
22
import { useFire } from '../../context';
33
import { timestamp } from '../../utils/addTimestamp';
44
import { isEmpty } from '../../utils/isEmpty';
5+
import { convertToWithUser } from '../../utils/convertToWithUser';
56

67
type UseAddType = [boolean, null | Error, AddFunction]
78
type AddFunction = (data: object) => void
@@ -17,6 +18,9 @@ export const useAdd = (collection: string): UseAddType => {
1718
const [loading, setLoading] = useState<boolean>(false);
1819
const [error, setError] = useState<null | Error>(null);
1920

21+
// converting collection to contain user id if `__user` was passed in
22+
const withUserCollection = convertToWithUser(collection);
23+
2024
/**
2125
* Function used to set a document in the firestore
2226
* @param data - an object that will be set in the firestore
@@ -27,6 +31,7 @@ export const useAdd = (collection: string): UseAddType => {
2731
*/
2832
const addFunction = (data: object) => {
2933
setLoading(true);
34+
setError(null);
3035
if (isEmpty(data)) {
3136
setError(new Error('You need to specify the data you want to add'));
3237
setLoading(false);
@@ -42,7 +47,7 @@ export const useAdd = (collection: string): UseAddType => {
4247
};
4348

4449
(async () => {
45-
const ref = firestore!.collection(collection);
50+
const ref = firestore!.collection(withUserCollection);
4651
try {
4752
await ref.add(timestampedData);
4853
setLoading(false);

src/firestore/write/useDelete.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export const useDelete = (collection: string): UseDeleteType => {
2424
*/
2525
const deleteFunction = (doc: string): void => {
2626
setLoading(true);
27+
setError(null);
2728
if (!doc) {
2829
setError(new Error('You need to pass an uid of the document you want to delete'));
2930
setLoading(false);

0 commit comments

Comments
 (0)