From eb1029a37b8278d0b280fad0ff916a85f40096c8 Mon Sep 17 00:00:00 2001 From: Scott Prue Date: Wed, 30 Aug 2017 17:59:38 -0700 Subject: [PATCH 1/3] Redux example updated with reducer. --- docs/redux.md | 156 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 122 insertions(+), 34 deletions(-) diff --git a/docs/redux.md b/docs/redux.md index 51f65e43..fcd02867 100644 --- a/docs/redux.md +++ b/docs/redux.md @@ -10,72 +10,160 @@ when it comes to integrating with other modules such a [`react-redux`](https://g To add `react-redux-firebase` to your project: 1. Run `npm i --save react-redux-firebase@canary` *we point to canary here to get current progress with v2.0.0* 1. Pass `react-native-firebase` instance into `reactReduxFirebase` when creating store: + **reducers.js** + ```js + import { combineReducers } from 'redux' + import { firebaseStateReducer } from 'react-redux-firebase' + export const makeRootReducer = (asyncReducers) => { + return combineReducers({ + // Add sync reducers here + firebase: firebaseStateReducer, + ...asyncReducers + }) + } + + export default makeRootReducer + + // Useful for injecting reducers as part of async routes + export const injectReducer = (store, { key, reducer }) => { + store.asyncReducers[key] = reducer + store.replaceReducer(makeRootReducer(store.asyncReducers)) + } + ``` + + **createStore.js** ```js import { applyMiddleware, compose, createStore } from 'redux'; - import { getFirebase } from 'react-redux-firebase' + import { getFirebase, reactReduxFirebase } from 'react-redux-firebase'; import RNFirebase from 'react-native-firebase'; + import makeRootReducer from './reducers'; const reactNativeFirebaseConfig = { debug: true }; - - const firebase = RNFirebase.initializeApp(reactNativeFirebaseConfig); - // for more config options, visit http://docs.react-redux-firebase.com/history/v2.0.0/docs/api/compose.html const reduxFirebaseConfig = { userProfile: 'users', // save users profiles to 'users' collection - } + }; - const middleware = [ - thunk.withExtraArgument({ getFirebase }), - // place other middleware here - ]; + export default (initialState = {}) => { + // initialize firebase + const firebase = RNFirebase.initializeApp(reactNativeFirebaseConfig); - const store = createStore( - reducer, - {}, // initial state - compose( - reactReduxFirebase(firebase, reduxConfig), // pass in react-native-firebase instance instead of config - applyMiddleware(...middleware) + const middleware = [ + // make getFirebase available in third argument of thunks + thunk.withExtraArgument({ getFirebase }), + ]; + + const store = createStore( + makeRootReducer(), + initialState, // initial state + compose( + reactReduxFirebase(firebase, reduxConfig), // pass initialized react-native-firebase app instance + applyMiddleware(...middleware) + ) ) - ) + } ``` + **index.js** + ```js + import React from 'react'; + import { Provider } from 'react-redux'; + import createStore from './createStore'; + import Todos from './Todos'; + + // Store Initialization + const initialState = { firebase: {} }; + const store = createStore(initialState); + + export default const Main = () => ( + + + + ); + ``` + 1. Then in your components you can use `firebaseConnect` to gather data from Firebase and place it into redux: + **Todos.js** ```js - import { isLoaded } from 'react-redux-firebase' import { compose } from 'redux'; - const Todos = ({ todos }) => { + import { View, Text, StyleSheet } from 'react-native' + import { isLoaded, isEmpty } from 'react-redux-firebase'; + import MessageView from './MessageView'; + + const testTodo = { text: 'Build Things', isComplete: false } + + const Todos = ({ todos, firebase }) => { if (!isLoaded(todos)) { - return
Loading...
+ return } if (isEmpty(todos)) { - return
No Todos Found
+ return ( + firebase.push('todos', testTodo)} + showNew + /> + ) } return ( -
- Object.keys(todos).map((key, id) => ( -
- {todos[key].text} - Complete: {todos[key].isComplete} -
- )) -
+ + Todos + { + Object.keys(todos).map((key, id) => ( + + {todos[key].text} + Complete: {todos[key].isComplete} + + )) + } + ) - } + }; - compose( + export default compose( firebaseConnect([ - { path: 'todos' } + { path: 'todos' } // create listener for firebase data -> redux ]), - connect(({ firebase: { data: { todos } } }) => { - todos + connect((state) => { + todos: state.firebase.data.todos, // todos data from redux -> props.todos }) )(Todos) ``` + Notice how `connect` is still used to get data out of `redux` since `firebaseConnect` only loads data **into** redux. -Notice how `connect` is still used to get data out of `redux` since `firebaseConnect` only loads data **into** redux. + **MessageView.js** + ```js + import { View, Text, StyleSheet } from 'react-native' + + const MessageView = ({ message, showNew = null, onNewTouch }) => ( + + {message} + { + showNew && + + Save + + } + + ); + + export default MessageView; + + const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center' + }, + button: { + height: 100, + marginTop: 10 + } + }); + ``` For more details, please visit [`react-redux-firebase`'s react-native section](http://docs.react-redux-firebase.com/history/v2.0.0/docs/recipes/react-native.html#native-modules). From d043f0b85bec3abc7c83195e3afda1e92a69a42b Mon Sep 17 00:00:00 2001 From: Scott Prue Date: Thu, 31 Aug 2017 00:24:43 -0700 Subject: [PATCH 2/3] Example simplified. --- docs/redux.md | 191 +++++++++++++++++++++++++++++--------------------- 1 file changed, 110 insertions(+), 81 deletions(-) diff --git a/docs/redux.md b/docs/redux.md index fcd02867..f343c3a9 100644 --- a/docs/redux.md +++ b/docs/redux.md @@ -8,35 +8,38 @@ when it comes to integrating with other modules such a [`react-redux`](https://g [`react-redux-firebase`](http://docs.react-redux-firebase.com/history/v2.0.0) provides simplified and standardized common redux/firebase logic. To add `react-redux-firebase` to your project: -1. Run `npm i --save react-redux-firebase@canary` *we point to canary here to get current progress with v2.0.0* -1. Pass `react-native-firebase` instance into `reactReduxFirebase` when creating store: +1. Run `npm i --save react-redux react-redux-firebase@canary` *we point to canary here to get current progress with v2.0.0* +1. Add `firebaseStateReducer` under `firebase` key within reducer: + **reducers.js** ```js - import { combineReducers } from 'redux' - import { firebaseStateReducer } from 'react-redux-firebase' + import { combineReducers } from 'redux'; + import { firebaseStateReducer } from 'react-redux-firebase'; export const makeRootReducer = (asyncReducers) => { return combineReducers({ // Add sync reducers here firebase: firebaseStateReducer, ...asyncReducers - }) - } + }); + }; - export default makeRootReducer + export default makeRootReducer; // Useful for injecting reducers as part of async routes export const injectReducer = (store, { key, reducer }) => { store.asyncReducers[key] = reducer store.replaceReducer(makeRootReducer(store.asyncReducers)) - } + }; ``` +1. Pass `react-native-firebase` instance into `reactReduxFirebase` when creating store: **createStore.js** ```js import { applyMiddleware, compose, createStore } from 'redux'; - import { getFirebase, reactReduxFirebase } from 'react-redux-firebase'; import RNFirebase from 'react-native-firebase'; + import { getFirebase, reactReduxFirebase } from 'react-redux-firebase'; + import thunk from 'redux-thunk'; import makeRootReducer from './reducers'; const reactNativeFirebaseConfig = { @@ -47,7 +50,7 @@ To add `react-redux-firebase` to your project: userProfile: 'users', // save users profiles to 'users' collection }; - export default (initialState = {}) => { + export default (initialState = { firebase: {} }) => { // initialize firebase const firebase = RNFirebase.initializeApp(reactNativeFirebaseConfig); @@ -60,12 +63,15 @@ To add `react-redux-firebase` to your project: makeRootReducer(), initialState, // initial state compose( - reactReduxFirebase(firebase, reduxConfig), // pass initialized react-native-firebase app instance + reactReduxFirebase(firebase, reduxFirebaseConfig), // pass initialized react-native-firebase app instance applyMiddleware(...middleware) ) - ) - } + ); + return store; + }; ``` +1. Wrap in `Provider` from `react-redux`: + **index.js** ```js import React from 'react'; @@ -75,95 +81,118 @@ To add `react-redux-firebase` to your project: // Store Initialization const initialState = { firebase: {} }; - const store = createStore(initialState); + let store = createStore(initialState); - export default const Main = () => ( + const Main = () => ( ); + + export default Main; ``` -1. Then in your components you can use `firebaseConnect` to gather data from Firebase and place it into redux: +1. Then you can use the `firebaseConnect` HOC to wrap your components. It helps to set listeners which gather data from Firebase and place it into redux: - **Todos.js** + **Home.js** ```js + import React from 'react'; import { compose } from 'redux'; - import { View, Text, StyleSheet } from 'react-native' - import { isLoaded, isEmpty } from 'react-redux-firebase'; - import MessageView from './MessageView'; + import { connect } from 'react-redux'; + import { isLoaded, isEmpty, firebaseConnect } from 'react-redux-firebase'; + import { View, Text, StyleSheet, ActivityIndicator } from 'react-native'; + import NewTodo from './NewTodo'; + import Todos from './Todos'; - const testTodo = { text: 'Build Things', isComplete: false } - - const Todos = ({ todos, firebase }) => { - if (!isLoaded(todos)) { - return + class Home extends React.Component { + state = { + text: null } - if (isEmpty(todos)) { + + completeTodo = (key, todo) => { + return this.props.firebase.update(`todos/${key}`, { done: !todo.done }) + } + + addTodo = () => { + const { text } = this.state; + return this.props.firebase.push('todos', { text, completed: false }); + } + + render() { + const { todos } = this.props; + return ( - firebase.push('todos', testTodo)} - showNew - /> - ) + + Todos + this.setState({text: v})} + /> + { + !isLoaded(todos) + ? + : null + } + { + isLoaded(todos) && !isEmpty(todos) + ? + + : + + No Todos Found + + } + + ); } - return ( - - Todos - { - Object.keys(todos).map((key, id) => ( - - {todos[key].text} - Complete: {todos[key].isComplete} - - )) - } - - ) - }; + } export default compose( firebaseConnect([ - { path: 'todos' } // create listener for firebase data -> redux + // create listener for firebase data -> redux + { path: 'todos', queryParams: ['limitToLast=15'] } ]), - connect((state) => { - todos: state.firebase.data.todos, // todos data from redux -> props.todos - }) - )(Todos) + connect((state) => ({ + // todos: state.firebase.data.todos, // todos data object from redux -> props.todos + todos: state.firebase.ordered.todos, // todos ordered array from redux -> props.todos + })) + )(Home); + ``` + + **Todos.js** + ```js + import React from 'react' + import { + View, + Text, + StyleSheet, + FlatList, + TouchableHighlight + } from 'react-native'; + + const Todos = ({ todos, onItemTouch }) => ( + ( + onItemTouch(key, value)}> + + {value.text} + Done: {value.done === true ? 'True' : 'False'} + + + )} + /> + ) + + export default Todos; ``` Notice how `connect` is still used to get data out of `redux` since `firebaseConnect` only loads data **into** redux. - **MessageView.js** - ```js - import { View, Text, StyleSheet } from 'react-native' - - const MessageView = ({ message, showNew = null, onNewTouch }) => ( - - {message} - { - showNew && - - Save - - } - - ); - - export default MessageView; - - const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center' - }, - button: { - height: 100, - marginTop: 10 - } - }); - ``` +Full source with styling available [in the react-native-firebase example for react-redux-firebase](https://github.com/prescottprue/react-redux-firebase/examples/complete/react-native-firebase) For more details, please visit [`react-redux-firebase`'s react-native section](http://docs.react-redux-firebase.com/history/v2.0.0/docs/recipes/react-native.html#native-modules). From 573355b02f6ae9306efeb235e058b558238585a8 Mon Sep 17 00:00:00 2001 From: Scott Prue Date: Thu, 31 Aug 2017 00:29:23 -0700 Subject: [PATCH 3/3] Clarified pre-install instructions. --- docs/redux.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/redux.md b/docs/redux.md index f343c3a9..5e57b3ff 100644 --- a/docs/redux.md +++ b/docs/redux.md @@ -8,7 +8,8 @@ when it comes to integrating with other modules such a [`react-redux`](https://g [`react-redux-firebase`](http://docs.react-redux-firebase.com/history/v2.0.0) provides simplified and standardized common redux/firebase logic. To add `react-redux-firebase` to your project: -1. Run `npm i --save react-redux react-redux-firebase@canary` *we point to canary here to get current progress with v2.0.0* +1. Make sure you already have `redux`, `react-redux`, `redux-thunk` installed (if not, run `npm i --save redux react-redux redux-thunk`) +1. Run `npm i --save react-redux-firebase@canary` *we point to canary here to get current progress with v2.0.0* 1. Add `firebaseStateReducer` under `firebase` key within reducer: **reducers.js** @@ -32,7 +33,7 @@ To add `react-redux-firebase` to your project: store.replaceReducer(makeRootReducer(store.asyncReducers)) }; ``` -1. Pass `react-native-firebase` instance into `reactReduxFirebase` when creating store: +1. Pass `react-native-firebase` App instance into `reactReduxFirebase` when creating store: **createStore.js** ```js @@ -61,7 +62,7 @@ To add `react-redux-firebase` to your project: const store = createStore( makeRootReducer(), - initialState, // initial state + initialState, compose( reactReduxFirebase(firebase, reduxFirebaseConfig), // pass initialized react-native-firebase app instance applyMiddleware(...middleware) @@ -70,6 +71,7 @@ To add `react-redux-firebase` to your project: return store; }; ``` + 1. Wrap in `Provider` from `react-redux`: **index.js** @@ -92,7 +94,7 @@ To add `react-redux-firebase` to your project: export default Main; ``` -1. Then you can use the `firebaseConnect` HOC to wrap your components. It helps to set listeners which gather data from Firebase and place it into redux: +1. Then you can use the `firebaseConnect` HOC to wrap your components. It makes it easy to set listeners which gather data from Firebase and place it into redux: **Home.js** ```js