Skip to content

Commit 8a9fa33

Browse files
prescottprueilluministmacinjokemarkoelezdzoba
authored
v3.1.2 (#872)
* fix(types): add types for `onAttemptCollectionDelete` to fix `implicit any` error (#870) - @macinjoke * fix(populate): handle firestore list type in populate (#871) - @illuminist * fix(types): add missing `onAuthStateChanged` for config object - @illuminist * fix(types): relax typing for `UserProfile` to be generic object - @illuminist * fix(types): make Schema the second generic parameter (#826) * chore(docs): add a typescript page to the recipes section of the docs (explains passing schema to reducer) Co-authored-by: illuminist <[email protected]> Co-authored-by: macinjoke <[email protected]> Co-authored-by: Marko Elez <[email protected]> Co-authored-by: Chris Dzoba <[email protected]>
1 parent a9a9892 commit 8a9fa33

File tree

22 files changed

+3675
-1571
lines changed

22 files changed

+3675
-1571
lines changed

docs/recipes/typescript.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Typescript
2+
3+
## Passing Schema To Reducer
4+
5+
**reducer.ts**
6+
7+
```ts
8+
import { combineReducers } from 'redux'
9+
import { firebaseReducer, FirebaseReducer } from 'react-redux-firebase'
10+
11+
interface UserProfile {
12+
email: string
13+
}
14+
15+
export interface TodoValue {
16+
text: string
17+
done: boolean
18+
}
19+
20+
// create schema for the DB
21+
interface DBSchema {
22+
todos: TodoValue
23+
[name: string]: any
24+
}
25+
26+
interface RootState {
27+
firebase: FirebaseReducer.Reducer<UserProfile, DBSchema>
28+
// firestore: FirestoreReducer.Reducer;
29+
}
30+
31+
const rootReducer = combineReducers<RootState>({
32+
firebase: firebaseReducer
33+
})
34+
35+
export type AppState = ReturnType<typeof rootReducer>
36+
37+
export default rootReducer
38+
```
39+
40+
Then in components, `AppState` can be used within selectors:
41+
42+
**Todo.tsx**
43+
44+
```tsx
45+
import React from "react";
46+
import { isLoaded, isEmpty, useFirebaseConnect } from "react-redux-firebase";
47+
import { AppState } from './reducer'
48+
import Todo from './Todo'
49+
import { useSelector } from "react-redux";
50+
51+
export default function Todos() {
52+
useFirebaseConnect([{ path: 'todos', queryParams: ['limitToLast=10'] }])
53+
const todos = useSelector((state: AppState) => {
54+
return state.firebase.ordered.todos
55+
})
56+
57+
if (!isLoaded(todos)) {
58+
return (
59+
<div >
60+
Loading...
61+
</div>
62+
);
63+
}
64+
65+
if (isEmpty(todos)) {
66+
return (
67+
<div >
68+
No Todos Found
69+
</div>
70+
);
71+
}
72+
73+
return (
74+
<div className="Todos">
75+
{
76+
todos && todos.map((todoItem) => {
77+
return <Todo key={todoItem.key} todoId={todoItem.key} />
78+
})
79+
}
80+
</div>
81+
);
82+
}
83+
```

examples/complete/material/.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module.exports = {
2-
'extends': ['react-app', 'prettier', 'prettier/react'],
2+
'extends': ['airbnb', 'airbnb/hooks', 'prettier', 'prettier/react'],
33
root: true,
44
parser: 'babel-eslint',
55
plugins: ['import', 'babel', 'react', 'react-hooks', 'prettier'],
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
module.exports = {
2+
parser: '@typescript-eslint/parser',
3+
'extends': [
4+
'airbnb-base',
5+
'prettier',
6+
'plugin:@typescript-eslint/recommended',
7+
'prettier/@typescript-eslint',
8+
'react-app',
9+
'prettier',
10+
'prettier/react'
11+
],
12+
root: true,
13+
plugins: ['@typescript-eslint', 'import', 'babel', 'react', 'react-hooks', 'prettier' ],
14+
settings: {
15+
'import/resolver': {
16+
node: {
17+
moduleDirectory: ['node_modules', '/'],
18+
extensions: ['.js', '.jsx', '.ts', '.tsx']
19+
}
20+
},
21+
react: {
22+
version: '16.0'
23+
}
24+
},
25+
env: {
26+
browser: true,
27+
node: true
28+
},
29+
rules: {
30+
'@typescript-eslint/no-explicit-any': 0,
31+
'import/prefer-default-export': 0,
32+
'no-shadow': 0,
33+
'consistent-return': 0,
34+
'no-new': 0,
35+
'new-cap': 0,
36+
'no-return-await': 2,
37+
'import/extensions': 0,
38+
'react-hooks/rules-of-hooks': 'error',
39+
'react-hooks/exhaustive-deps': 'warn',
40+
'prettier/prettier': [
41+
'error',
42+
{
43+
singleQuote: true,
44+
trailingComma: 'none',
45+
semi: false,
46+
bracketSpacing: true,
47+
jsxBracketSameLine: true,
48+
printWidth: 80,
49+
tabWidth: 2,
50+
useTabs: false
51+
}
52+
]
53+
}
54+
}

examples/complete/typescript/package.json

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"build": "react-scripts build",
88
"test": "react-scripts test",
99
"eject": "react-scripts eject",
10-
"lint": "tslint 'src/**/*.ts'",
10+
"lint": "eslint 'src/**/*.ts'",
1111
"lint:fix": "npm run lint -- --fix"
1212
},
1313
"dependencies": {
@@ -18,14 +18,25 @@
1818
"redux": "^4.0.4"
1919
},
2020
"devDependencies": {
21-
"@types/jest": "24.0.11",
22-
"@types/node": "11.13.0",
23-
"@types/react": "16.8.12",
24-
"@types/react-dom": "16.8.3",
25-
"@types/react-redux": "^7.1.1",
26-
"react-scripts": "3.1.0",
27-
"tslint": "^5.18.0",
28-
"typescript": "3.4.1"
21+
"@types/jest": "25.1.2",
22+
"@types/node": "13.7.0",
23+
"@types/react": "16.9.19",
24+
"@types/react-dom": "16.9.5",
25+
"@types/react-redux": "^7.1.7",
26+
"@typescript-eslint/eslint-plugin": "^2.19.0",
27+
"@typescript-eslint/parser": "^2.19.0",
28+
"eslint": "^6.8.0",
29+
"eslint-config-airbnb": "^18.0.1",
30+
"eslint-config-prettier": "^6.10.0",
31+
"eslint-plugin-babel": "^5.3.0",
32+
"eslint-plugin-import": "^2.20.1",
33+
"eslint-plugin-jsx-a11y": "^6.2.3",
34+
"eslint-plugin-prettier": "^3.1.2",
35+
"eslint-plugin-react": "^7.18.3",
36+
"eslint-plugin-react-hooks": "^2.3.0",
37+
"prettier": "^1.19.1",
38+
"react-scripts": "3.3.1",
39+
"typescript": "3.7.5"
2940
},
3041
"eslintConfig": {
3142
"extends": "react-app"

examples/complete/typescript/src/AddTodo.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import React from "react";
2-
import { ExtendedFirebaseInstance, useFirebase} from "react-redux-firebase";
2+
import { ExtendedFirebaseInstance, useFirebase } from "react-redux-firebase";
33

44
function AddTodo() {
55
const firebase: ExtendedFirebaseInstance = useFirebase();
6+
67
function handleAddClick() {
78
firebase.push("todos", { done: false, text: "Example todo" });
89
}

examples/complete/typescript/src/Home.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import React, { FunctionComponent } from "react";
1+
import React from "react";
2+
import Todos from "./Todos";
23
import AddTodo from "./AddTodo";
34
import "./App.css";
45
import logo from "./logo.svg";
@@ -7,19 +8,13 @@ function Home() {
78
return (
89
<div className="Home">
910
<header className="App-header">
10-
<img src={logo} className="App-logo" alt="logo" />
1111
<p>
1212
Edit <code>src/App.tsx</code> and save to reload.
1313
</p>
14-
<a
15-
className="App-link"
16-
href="https://reactjs.org"
17-
target="_blank"
18-
rel="noopener noreferrer"
19-
>
20-
Learn React
21-
</a>
14+
<div>
15+
<Todos />
2216
<AddTodo />
17+
</div>
2318
</header>
2419
</div>
2520
);

examples/complete/typescript/src/List.tsx

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from "react";
2+
import { AppState, TodoValue } from './reducer'
3+
import { useSelector } from "react-redux";
4+
import { useFirebase } from 'react-redux-firebase'
5+
6+
interface TodoProps {
7+
todoId: string
8+
}
9+
10+
function Todo({ todoId }: TodoProps) {
11+
const todo: TodoValue = useSelector((state: AppState) => {
12+
return state.firebase.data.todos && state.firebase.data.todos[todoId]
13+
})
14+
const firebase = useFirebase()
15+
function toggleDoneState() {
16+
firebase.update(`todos/${todoId}`, { done: !todo.done })
17+
}
18+
19+
return (
20+
<div className="Todo">
21+
<input type="checkbox" onClick={toggleDoneState} />
22+
{todo.text}
23+
</div>
24+
);
25+
}
26+
27+
export default Todo;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import React from "react";
2+
import { isLoaded, isEmpty, useFirebaseConnect } from "react-redux-firebase";
3+
import { AppState } from './reducer'
4+
import Todo from './Todo'
5+
import { useSelector } from "react-redux";
6+
7+
function Todos() {
8+
useFirebaseConnect([{ path: 'todos', queryParams: ['limitToLast=10'] }])
9+
const todos = useSelector((state: AppState) => {
10+
return state.firebase.ordered.todos
11+
})
12+
13+
if (!isLoaded(todos)) {
14+
return (
15+
<div >
16+
Loading...
17+
</div>
18+
);
19+
}
20+
21+
if (isEmpty(todos)) {
22+
return (
23+
<div >
24+
No Todos Found
25+
</div>
26+
);
27+
}
28+
29+
return (
30+
<div className="Todos">
31+
{
32+
todos && todos.map((todoItem) => {
33+
return <Todo key={todoItem.key} todoId={todoItem.key} />
34+
})
35+
}
36+
</div>
37+
);
38+
}
39+
40+
export default Todos;

0 commit comments

Comments
 (0)