Hi I am trying to learn firebase. Now I am trying to follow what is inside the github doc.
Like to gitHub
This is my index.js file
const rfConfig = {}; // optional redux-firestore Config Options
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: 'something',
authDomain: 'something',
databaseURL: 'something',
projectId: 'something',
storageBucket: 'something.com',
messagingSenderId: 'something',
appId: '1:something',
measurementId: 'G-something',
};
firebase.initializeApp(firebaseConfig);
// Initialize Cloud Firestore through Firebase
firebase.firestore();
// Add reduxFirestore store enhancer to store creator
const createStoreWithFirebase = compose(
reduxFirestore(firebase, rfConfig), // firebase instance as first argument, rfConfig as optional second
)(createStore);
// Add Firebase to reducers
const rootReducer = combineReducers({
firestore: firestoreReducer,
});
// Create store with reducers and initial state
const initialState = {};
const store = createStoreWithFirebase(rootReducer, initialState);
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
My folder got 3 components. 1 is for adding todo. 1 is for displaying todo. & the last 1 is combination of the first two
Here is my app component & TodoShow Component
const App = () => {
return (
<div>
<TodoShow/>
</div>
)
}
const TodoShow = () => {
return (
<div>
<Todo/>
{/* <Todos/> */}
</div>
)
}
Inside the Todo button component I want to add a new todo when i click on a button
import { useFirebase } from 'react-redux-firebase'
export default function Todo() {
const firebase = useFirebase()
function addSampleTodo() {
const sampleTodo = { text: 'Sample', done: false }
return firebase.push('todos', sampleTodo)
}
return (
<div>
<h1>New Sample Todo</h1>
<button onClick={addSampleTodo}>Add</button>
</div>
)
}
But when I click on the button, The app doesn't know firebase.
Here is the photo
Is there something i am missing here? I have already install firebase,react-redux-firebase,redux-firestore
You need to render a ReactReduxFirebaseProvider near the top of your component tree. This is what useFirebase is trying to access, so without one, you get undefined.
const rrfConfig = {
userProfile: 'users'
// useFirestoreForProfile: true // Firestore for Profile instead of Realtime DB
}
const rrfProps = {
firebase,
config: rrfConfig,
dispatch: store.dispatch
// createFirestoreInstance // <- needed if using firestore
}
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<ReactReduxFirebaseProvider {...rrfProps}>
<App />
</ReactReduxFirebaseProvider>
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
For more info see this section of the documentation: https://github.com/prescottprue/react-redux-firebase#use
Related
I am trying to implement persistent login for my application. I am facing error
No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app/no-app)
I tried solving it by looking into the existing issues but does not quite fit into this use case.
I have initialised my firebase from App.js and then after navigating to SplashScreen (AuthStack based on a state) I am calling an action creator from ComponentDidMount inside of SplashScreen. In that action creator I am checking the Auth State(if user returns non null then I am updating the state to move to AppStack).
App.js
class App extends Component {
componentDidMount() {
const firebaseConfig = {
apiKey: 'AIzaSyDOpO3TjIN4lCCufMZWKs7eZYd86SJB0o8',
authDomain: 'vocabs-a3f7e.firebaseapp.com',
databaseURL: 'https://vocabs-a3f7e.firebaseio.com',
projectId: 'vocabs-a3f7e',
storageBucket: 'vocabs-a3f7e.appspot.com',
messagingSenderId: '938659592890',
appId: '1:938659592890:web:7d309f3751892982066083',
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
}
render() {
return (
<Provider store={createStore(reducers, {}, applyMiddleware(ReduxThunk))}>
<NavigationContainer>
<MainRoute />
</NavigationContainer>
</Provider>
);
}
Splash screen
class SplashScreen extends Component {
componentDidMount() {
setTimeout(this.renderSignInForm, 1000);
//this.renderSignInForm();
}
renderSignInForm = () => {
console.log('inside async');
this.props.persistantSignIn();
//const userData = this.checkUser();
if (this.props.userData) {
console.log('hit user true' + this.props.userData);
} else {
// No user is signed in.
console.log('hit user false' + this.props.userData);
this.props.navigation.navigate('SignInForm');
}
};
render(){
return(
/*some Code Here*/
);
}
ActionCreator
export const persistantSignIn = () => {
return (dispatch) => {
firebase
.auth()
.onAuthStateChanged.then((userData) => {
console.log(userData);
dispatch({
type: PERSISTANT_SIGN_IN,
payload: userData,
});
})
.catch((error) => {
console.log('something is wronggggggggg');
throw error;
});
};
};
MainRoute.js
class MainRoute extends Component {
render() {
return this.props.isSignedIn ? <AppStack /> : <AuthStack />;
}
}
I am using redux and react router.
I want to test that a route param shows up on the page.
test('route param is displayed', async () => {
const { queryByText } = customRender(
<EditCard />,
{
route: '/card/1554990887217',
}
);
const cardId = queryByText(/1554990887217/);
await waitForElement(() => cardId);
})
my custom render wraps router and redux like so:
export const customRender = (
ui,
{
route = '/',
history = createMemoryHistory({ initialEntries: [route] }),
initialState,
store = createStore(rootReducer, initialState),
...options
} = {}
) => ({
...rtl(
<Provider store={store}>
<Router history={history}>{ui}</Router>
</Provider>,
options
),
history,
});
The route param just doesn't show up in the test. It just errors with a time out.
It works on the page though, as in everything works as expected if I start the app up and test it manually.
You need to pass the route in as well.
const { queryByText } = render(
<Route path="/card/:cardId">
<EditCard />
</Route>,
{
route: '/card/1554990887217',
}
);
New to React/Redux combo and trying to work through an issue.
When a user first visits or logs in / a fetch_user api request is made. The intention is that the page would display differently based on their login status. In redux dev tools I can see the state being updated and fields being populated to 'auth' after the initial state, however, while I am in a subcomponent of the app the value is seen as undefined. Please let me know if you need any more information. Thanks in advance.
// app.js
const initialState = {};
const history = createHistory();
const store = configureStore(initialState, history);
const MOUNT_NODE = document.getElementById('app');
const render = messages => {
ReactDOM.render(
<Provider store={store}>
<LanguageProvider messages={messages}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</LanguageProvider>
</Provider>,
MOUNT_NODE,
);
};
// index.js
class App extends React.Component {
componentDidMount() {
console.log('here');
this.props.fetchUser();
}
render() {
return (
<ThemeWrapper>
<AppContext.Consumer>
.....
App.propTypes = {
fetchUser: PropTypes.any.isRequired
};
export default withRouter(connect(null, actions)(App));
import { FETCH_USER } from '../actions/types';
export default function (state = null, action) {
switch (action.type) {
case FETCH_USER:
console.log('1');
return action.payload || false;
default:
return state;
}
}
// actions
export const fetchUser = () => async dispatch => {
const res = await axios.get('/api/current_user');
// res is the output of the axios request
dispatch({ type: FETCH_USER, payload: res.data });
};
// Banner.js - auth = undefined
render() {
console.log(this.props);
// === auth = undefined. I may be accessing it incorrectly
const mapStateToProps = state => ({
gradient: state.getIn([reducerUI, 'gradient']),
chat: state.getIn([chatUI, 'chatSelected']),
auth: state.auth
});
const BannerMaped = connect(
mapStateToProps,
)(Banner);
// configure store
export default function configureStore(initialState = {}, history) {
// Create the store with two middlewares
// 1. sagaMiddleware: Makes redux-sagas work
// 2. routerMiddleware: Syncs the location/URL path to the state
const middlewares = [sagaMiddleware, routerMiddleware(history), reduxThunk];
const enhancers = [applyMiddleware(...middlewares)];
// If Redux DevTools Extension is installed use it, otherwise use Redux compose
/* eslint-disable no-underscore-dangle, indent */
const composeEnhancers =
process.env.NODE_ENV !== 'production' &&
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
// TODO Try to remove when `react-router-redux` is out of beta, LOCATION_CHANGE should not be fired more than once after hot reloading
// Prevent recomputing reducers for `replaceReducer`
shouldHotReload: false,
})
: compose;
/* eslint-enable */
const store = createStore(
createReducer(),
fromJS(initialState),
composeEnhancers(...enhancers),
);
// Extensions
store.runSaga = sagaMiddleware.run;
store.injectedReducers = {}; // Reducer registry
store.injectedSagas = {}; // Saga registry
// Make reducers hot reloadable, see http://mxs.is/googmo
if (module.hot) {
module.hot.accept('./reducers', () => {
store.replaceReducer(createReducer(store.injectedReducers));
});
}
return store;
}
Redux store updates are mapped to individual components and not the whole app.
This line means, only the Banner component will be re-rendered when the store is updated and not your entire app.
const BannerMaped = connect(
mapStateToProps,
)(Banner);
So wherever your Banner component is, every time fetchUser() response succeeds and updates the store, only your Banner component will be re-rendered. If you need to re-render other components, they should also subscribe to store with corresponding mapStateToProps.
You also need to pass dispatch actions in connect method. In your case, you have already make fetchUser() action. So, you can pass it in your connect method like this:
const BannerMaped = connect(
mapStateToProps,
fetchUser
)(Banner);
I think this will help.
I was doing everything correctly just not accessing the state object appropriately. Stared at this one a little too long.
const mapStateToProps = state => ({
gradient: state.getIn([reducerUI, 'gradient']),
chat: state.getIn([chatUI, 'chatSelected']),
auth: state.getIn(['auth'])
});
Trying to set up some testdata in React Native using Firebase. I have successfully installed using $yarn add firebase. I have added test data in FB like this:
FB data
And in my project I added the following code:
import * as firebase from 'firebase'
const firebaseConfig = {
apiKey: "AIzaSyBNKM6Ptbynkg5dEJkwMHNsZhUCsW2JqGE",
authDomain: "testproject-f4c9f.firebaseapp.com",
databaseURL: "https://testproject-f4c9f.firebaseio.com",
projectId: "testproject-f4c9f",
storageBucket: "testproject-f4c9f.appspot.com",
messagingSenderId: "48530616964"
}
firebase.initializeApp(firebaseConfig)
Then in the rendering:
let mytext = ""
let testing =
firebase.database().ref('testCategory/test1/FirstHeader');
testing.on('value', function(snapshot) {
mytext = snapshot.val()
});
return(
<View>
<Text>{mytext}</Text>
</View>
);
Running the app, nothing shows. Any ideas would be appreciated.
UPDATE:
I managed to get it right in the console.log with this code:
let child = ""
var ref = firebase.database().ref("testCategory");
ref.once("value")
.then(function(snapshot) {
child = snapshot.child("test1/testHeader").val()
console.log({child})
});
But for some reason I can't print it in the text output:
return(
<View>
<Text>{this.child}</Text>
</View>
);
It's just blank...
You need to pass the data from the callback to the view. You should use a state manager like Redux or MobX, but for this example, you can just use the component state.
This is what your component should look like.
class Hello extends Component {
state = {
child: ''
}
componentDidMount() {
firebase
.database()
.ref('testCategory')
.on('value')
.then(snapshot => {
const child = snapshot.child('test1/testHeader').val()
this.setState({
child
})
})
}
render() {
const { child } = this.state
return (
<View>
<Text>{child}</Text>
</View>
)
}
}
Tada!
I'm attempting to set up routing using react-router-redux with Immutable.js reducers.
I've set up the store using syncHistoryWithStore, and when I click on a Link, I can see that the correct ##router/LOCATION_CHANGE action is dispatched, that the store is correctly updated with the location information to the routing key of the base reducer, and that the URL is changing to the correct location.
But the child components of the new path don't render. The previous path's components are still rendered on the screen. They aren't re-rendered either, they just stay. When I look at the props that are passed to the parent component, the location prop still shows the previous route. It's as if the redux action was fired and nothing happened. No new props were passed down.
Here's my app.js
import configureStore from './config.redux/store';
// import selector for 'syncHistoryWithStore'
import { makeSelectLocationState } from './config.redux/selectors';
// root app
import App from './App';
import { createRoutes} from 'config.routes/routes';
// create redux store with history
const initialState = {};
const store = configureStore(initialState, browserHistory);
// sync history and store, as the react-router-redux reducer
const history = syncHistoryWithStore(browserHistory, store, {
selectLocationState: makeSelectLocationState(),
});
history.listen(location => {
console.log(location);
});
const rootRoute = createRoutes(store);
ReactDOM.render(
<Provider store={store}>
<MuiThemeProvider>
<Router
history={history}
routes={rootRoute}
render={
// Scroll to top when going to new page, imitating default browser behavior
applyRouterMiddleware(useScroll())
}
/>
</MuiThemeProvider>
</Provider>, document.getElementById('app')
);
store.js
const sagaMiddleware = createSagaMiddleware();
const logger = createLogger();
export default function configureStore(initialState = {}, history) {
// Create store with middleware
const middlewares = [
sagaMiddleware,
logger,
routerMiddleware(history)
];
const enhancers = [
applyMiddleware(...middlewares)
];
// If Redux DevTools Extension is installed use it, otherwise use Redux compose
/* eslint-disable no-underscore-dangle */
const composeEnhancers =
process.env.NODE_ENV !== 'production' &&
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose;
/* eslint-enable */
const store = createStore(
createReducer(),
fromJS(initialState),
composeEnhancers(...enhancers)
);
// Extensions
store.runSaga = sagaMiddleware.run;
store.asyncReducers = {}; // async reducer registry
// Make reducers hot reloadable, see http://mxs.is/googmo
/* istanbul ignore next */
if (module.hot) {
module.hot.accept('./reducers', () => {
require('./reducers').then((reducerModule) => {
const createReducers = reducerModule.default;
const nextReducers = createReducers(store.asyncReducers);
store.replaceReducer(nextReducers);
});
});
}
return store;
}
reducers.js
// initial routing state
const routeInitialState = fromJS({
locationBeforeTransition: null,
});
// merge route into the global application state
function routeReducer(state = routeInitialState, action) {
switch(action.type) {
case LOCATION_CHANGE:
return state.merge({
locationBeforeTransition: action.payload,
});
default:
return state;
}
}
/**
* Create the main reducer with async loaded ones
*
*/
export default function createReducer(asyncReducers) {
return combineReducers({
routing: routeReducer,
auth: globalReducer,
...asyncReducers
});
}
Any ideas? I've been trying to fix this for a couple days now.