Skip to content

Commit 2504b4f

Browse files
authored
v2.0.0-beta.18 (#345)
* feat(populate): `childAlias` for store results of populate on another parameter - #126 * feat(profile): Firestore support for `updateProfile` method - [issue 25 on redux-firestore](prescottprue/redux-firestore#25) * feat(storage): `progress` option added to `uploadFile` method - #346 * feat(storage): `uploadFile` default metadata written to DB now includes `createdAt` * feat(core): `redux-firestore` is no longer a dependency - managed by library user directly * fix(examples): Material-ui example updates (including moving `injectTapEventPlugin()` to `main.js`)
1 parent ef62203 commit 2504b4f

File tree

29 files changed

+1608
-1486
lines changed

29 files changed

+1608
-1486
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ sudo: false
33
language: node_js
44

55
node_js:
6-
- 6.11.3 # Still Used
6+
- 6.11.5 # Cloud Functions Runtime (Used for firebase-functions)
77
- 8 # L.T.S
88
- 9 # Current
99

README.md

+48-30
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,49 @@ export default compose(
157157
)(Todos)
158158
```
159159

160+
**Queries Based On Props**
161+
162+
It is common to make a detail page that loads a single item instead of a whole list of items. A query for a specific `Todos` can be created using
163+
164+
```jsx
165+
import React from 'react'
166+
import PropTypes from 'prop-types'
167+
import { connect } from 'react-redux'
168+
import { compose } from 'redux'
169+
import { firebaseConnect, getVal } from 'react-redux-firebase'
170+
171+
// Component enhancer that loads todo into redux then into the todo prop
172+
const enhance = compose(
173+
firebaseConnect((props) => [
174+
// Set listeners based on props (prop is route parameter from react-router in this case)
175+
return [
176+
{ path: `todos/${props.params.todoId}` }, // create todo listener
177+
// `todos/${props.params.todoId}` // equivalent string notation
178+
]
179+
}),
180+
connect(({ firebase }, props) => ({
181+
todo: getVal(firebase, `todos/${props.params.todoId}`), // lodash's get can also be used
182+
}))
183+
)
184+
185+
const Todo = ({ todo, firebase, params }) =>
186+
<div>
187+
<input
188+
name="isDone"
189+
type="checkbox"
190+
checked={todo.isDone}
191+
onChange={() =>
192+
firebase.update(`todos/${params.todoId}`, { done: !todo.isDone })
193+
}
194+
/>
195+
<span>{todo.label}</span>
196+
</div>
197+
198+
// Export enhanced component
199+
export default enhance(Todo)
200+
```
201+
202+
160203
**Load Data On Click**
161204

162205
```jsx
@@ -188,41 +231,16 @@ const Todos = ({ firebase }) => {
188231
)
189232
}
190233

234+
// Export enhanced component
191235
export default compose(
192236
withFirebase, // or firebaseConnect()
193-
connect(
194-
(state) => ({
195-
todos: state.firebase.data.todos,
196-
// profile: state.firebase.profile // load profile
197-
})
198-
)
237+
connect((state) => ({
238+
todos: state.firebase.data.todos,
239+
// profile: state.firebase.profile // load profile
240+
}))
199241
)(Todos)
200242
```
201243

202-
**Queries Based On State**
203-
`Todos` component from above examples
204-
205-
```jsx
206-
import React from 'react'
207-
import PropTypes from 'prop-types'
208-
import { connect } from 'react-redux'
209-
import { compose } from 'redux'
210-
import { firebaseConnect } from 'react-redux-firebase'
211-
212-
export default compose(
213-
firebaseConnect((props, store) => {
214-
const state = store.getState();
215-
// Get Todos stored by user UID
216-
return state.auth ? [`todos/${state.auth.uid}`] : []
217-
}),
218-
connect(
219-
(state) => ({
220-
todos: state.firebase.data.todos,
221-
// profile: state.firebase.profile // load profile
222-
})
223-
)
224-
)(Todos)
225-
```
226244

227245
## [Docs](http://react-redux-firebase.com)
228246
See full documentation at [react-redux-firebase.com](http://react-redux-firebase.com)

docs/getting_started.md

+49-99
Original file line numberDiff line numberDiff line change
@@ -11,38 +11,6 @@ npm install --save react-redux-firebase
1111

1212
Install peer dependencies: `npm i --save redux react-redux`
1313

14-
### Decorators
15-
16-
Though they are optional, it is highly recommended that you used decorators with this library. [The Simple Example](examples/simple) shows implementation without decorators, while [the Decorators Example](examples/decorators) shows the same application with decorators implemented.
17-
18-
A side by side comparison using [react-redux](https://github.com/reactjs/react-redux)'s `connect` function/HOC is the best way to illustrate the difference:
19-
20-
```jsx
21-
class SomeComponent extends Component {
22-
23-
}
24-
export default connect()(SomeComponent)
25-
```
26-
vs.
27-
28-
```jsx
29-
@connect()
30-
export default class SomeComponent extends Component {
31-
32-
}
33-
```
34-
35-
In order to enable this functionality, you will most likely need to install a plugin (depending on your build setup). For Webpack and Babel, you will need to make sure you have installed and enabled [babel-plugin-transform-decorators-legacy](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy) by doing the following:
36-
37-
1. run `npm i --save-dev babel-plugin-transform-decorators-legacy`
38-
2. Add the following line to your `.babelrc`:
39-
```json
40-
{
41-
"plugins": ["transform-decorators-legacy"]
42-
}
43-
```
44-
45-
4614
## Install
4715
```bash
4816
npm install --save react-redux-firebase
@@ -55,15 +23,15 @@ Include `firebase` in your combine reducers function:
5523

5624
```js
5725
import { combineReducers } from 'redux'
58-
import { firebaseStateReducer } from 'react-redux-firebase'
26+
import { firebaseReducer } from 'react-redux-firebase'
5927

6028
// Add firebase to reducers
6129
const rootReducer = combineReducers({
62-
firebase: firebaseStateReducer
30+
firebase: firebaseReducer
6331
})
6432
```
6533

66-
## Compose Function
34+
## Setting Up Store With Store Enhancer
6735

6836
```js
6937
import { compose } from 'redux'
@@ -84,7 +52,7 @@ const config = {
8452

8553
// Add redux Firebase to compose
8654
const createStoreWithFirebase = compose(
87-
reactReduxFirebase(firebaseConfig, config)
55+
reactReduxFirebase(firebase, config)
8856
)(createStore)
8957

9058
// Create store with reducers and initial state
@@ -95,76 +63,58 @@ View the [config section](/config.html) for full list of configuration options.
9563

9664
## Use in Components
9765

66+
**Queries Based On State**
67+
`Todos` component from above examples
68+
9869
```jsx
99-
import React, { Component } from 'react'
70+
import React from 'react'
10071
import PropTypes from 'prop-types'
10172
import { connect } from 'react-redux'
102-
import { firebaseConnect, isLoaded, isEmpty } from 'react-redux-firebase'
103-
104-
@firebaseConnect([
105-
'todos' // corresponds to 'todos' root on firebase
106-
])
107-
@connect(
108-
({ firebase: { data: { todos } } }) => ({ // state.firebase.data.todos
109-
// todos prop set to firebase data in redux under '/todos'
110-
todos,
111-
})
112-
)
113-
export default class Todos extends Component {
114-
static propTypes = {
115-
todos: PropTypes.object,
116-
firebase: PropTypes.object
117-
}
118-
119-
handleAdd = () => {
120-
const {newTodo} = this.refs
121-
const { firebase } = this.props
122-
// Add a new todo to firebase
123-
firebase.push('/todos', { text: newTodo.value, done: false })
124-
newTodo.value = ''
125-
}
126-
127-
render() {
128-
const { todos } = this.props;
129-
130-
// Build Todos list if todos exist and are loaded
131-
const todosList = !isLoaded(todos)
132-
? 'Loading'
133-
: isEmpty(todos)
134-
? 'Todo list is empty'
135-
: Object.keys(todos).map(
136-
(key, id) => (
137-
<TodoItem key={key} id={id} todo={todos[key]}/>
138-
)
139-
)
140-
141-
return (
142-
<div>
143-
<h1>Todos</h1>
144-
<ul>
145-
{todosList}
146-
</ul>
147-
<input type="text" ref="newTodo" />
148-
<button onClick={this.handleAdd}>
149-
Add
150-
</button>
151-
</div>
152-
)
153-
}
73+
import { compose } from 'redux'
74+
import { firebaseConnect } from 'react-redux-firebase'
75+
76+
export default compose(
77+
firebaseConnect((props) => {
78+
return [
79+
'todos'
80+
]
81+
}),
82+
connect(
83+
(state) => ({
84+
todos: state.firebase.data.todos,
85+
// profile: state.firebase.profile // load profile
86+
})
87+
)
88+
)(Todos)
89+
```
90+
91+
### Decorators
92+
93+
They are completely optional, but ES7 Decorators can be used. [The Simple Example](examples/simple) shows implementation without decorators, while [the Decorators Example](examples/decorators) shows the same application with decorators implemented.
94+
95+
A side by side comparison using [react-redux](https://github.com/reactjs/react-redux)'s `connect` function/HOC is the best way to illustrate the difference:
96+
97+
```jsx
98+
class SomeComponent extends Component {
99+
154100
}
101+
export default connect()(SomeComponent)
155102
```
103+
vs.
156104

157-
Alternatively, if you choose not to use decorators, your connect function will look like so:
105+
```jsx
106+
@connect()
107+
export default class SomeComponent extends Component {
158108

159-
```javascript
160-
const wrappedTodos = firebaseConnect([
161-
'todos'
162-
])(Todos)
109+
}
110+
```
163111

164-
export default connect(
165-
({ firebase: { data: { todos } } }) => ({
166-
todos,
167-
})
168-
)(wrappedTodos)
112+
In order to enable this functionality, you will most likely need to install a plugin (depending on your build setup). For Webpack and Babel, you will need to make sure you have installed and enabled [babel-plugin-transform-decorators-legacy](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy) by doing the following:
169113

114+
1. run `npm i --save-dev babel-plugin-transform-decorators-legacy`
115+
2. Add the following line to your `.babelrc`:
116+
```json
117+
{
118+
"plugins": ["transform-decorators-legacy"]
119+
}
170120
```

docs/populate.md

+43-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export default enhance(SomeComponent)
3434
* Population happens in two parts:
3535
1. `firebaseConnect` - based on populate settings, queries are created for associated keys to be replaced. Query results are stored in redux under the value of `root` in the populate settings.
3636
2. `connect` - Combine original data at path with all populate data (in redux from queries created by passing populate settings to `firebaseConnect`)
37-
* Populate creates a query for each key that is being replaced
37+
* Populate creates a query for each key that is being "populated", but does not create multiple queries for the same key
3838
* Results of populate queries are placed under their root
3939

4040
## Examples
@@ -135,10 +135,13 @@ ASDF123: {
135135
}
136136
```
137137

138-
##### Keep Object's Key
138+
##### Keep Object's Key {#keyProp}
139139

140140
Often when populating, you will want to keep the key that was originally there (before being replaced by populated value). This is supported through the use of `keyProp`:
141141

142+
143+
*NOTE:* Similar results also be accomplished using [`childAlias`](#childAlias) since child (key in this case) will be preserved if populate result is "aliased"
144+
142145
##### Example Query
143146
```javascript
144147
const populates = [
@@ -170,7 +173,44 @@ ASDF123: {
170173
}
171174
```
172175

173-
### Object's Parameter
176+
### Place Result On Another Parameter {#childAlias}
177+
178+
There is also the option to place the results of a populate on another parameter instead of replacing the original child (i.e. "alias" the child result). An example of this could be populating the `owner` parameter onto the `ownerObj` parameter, which would leave the `owner` parameter intact (since the child from the populate was "aliased" to `ownerObj`).
179+
180+
For more details including the initial feature request, checkout [issue #126](https://github.com/prescottprue/react-redux-firebase/issues/126).
181+
182+
##### Example
183+
```javascript
184+
const populates = [
185+
{ child: 'owner', root: 'users', childAlias: 'ownerObj' }
186+
]
187+
188+
const enhance = compose(
189+
firebaseConnect([
190+
{ path: '/todos', populates }
191+
// '/todos#populate=owner:users:email' // equivalent string notation
192+
]),
193+
connect(
194+
({ firebase }) => ({
195+
todos: populate(firebase, 'todos', populates),
196+
})
197+
)
198+
)
199+
```
200+
201+
##### Example Result
202+
203+
```javascript
204+
ASDF123: {
205+
text: 'Some Todo Item',
206+
owner: "Iq5b0qK2NtgggT6U3bU6iZRGyma2",
207+
ownerObj: {
208+
209+
}
210+
}
211+
```
212+
213+
### Object's Parameter {#childParam}
174214

175215
There is also the option to load a parameter from within a population object. An example of this could be populating the `owner` parameter with the `email` property of the `user` with a matching ID:
176216

0 commit comments

Comments
 (0)