react-redux-firebase firestore returns function and not object - react-redux-firebase

I'm trying to use firestore with react-redux-firebase on a React App, and when I try to access state.firestore it returns a function and no the object. I'll attach the code for initialization.
This is the app file.
import React from "react";
import ReactDOM from "react-dom";
import "./index.styles.ts";
import * as serviceWorker from "./serviceWorker";
import Theme from "./components/Theme";
import configureStore from "./store/configureStore";
import { Provider } from "react-redux";
import Routes from "routes";
import firebase from 'firebase/app'
import 'firebase/auth';
import 'firebase/firestore';
// import 'firebase/functions' // <- needed if using httpsCallable
import {
ReactReduxFirebaseProvider,
} from 'react-redux-firebase'
import { createFirestoreInstance } from 'redux-firestore';
const firebaseConfig = {
};
// react-redux-firebase config
const rrfConfig = {
userProfile: 'users',
useFirestoreForProfile: true // Firestore for Profile instead of Realtime DB
// enableClaims: true // Get custom claims along with the profile
}
// Initialize firebase instance
firebase.initializeApp(firebaseConfig);
firebase.firestore();
const store = configureStore();
const rrfProps = {
firebase,
config: rrfConfig,
dispatch: store.dispatch,
createFirestoreInstance
};
ReactDOM.render(
<Theme>
<Provider store={store}>
<ReactReduxFirebaseProvider {...rrfProps}>
<Routes />
</ReactReduxFirebaseProvider>
</Provider>
</Theme>,
document.getElementById("root")
);
serviceWorker.unregister();
According to the docs, this is basically what's needed to be able to access firestore.
This is the configureStore file
import { createBrowserHistory } from "history";
import { createStore, applyMiddleware, Store } from "redux";
import { routerMiddleware } from "connected-react-router";
import thunk from "redux-thunk";
import { History } from "history";
import { combineReducers, compose } from "redux";
import { connectRouter } from "connected-react-router";
import * as reducers from "./reducers";
import { firebaseReducer } from "react-redux-firebase";
import { reduxFirestore } from "redux-firestore";
export const history = createBrowserHistory();
const createRootReducer = (history: History<any>) =>
combineReducers({
router: connectRouter(history),
firebase: firebaseReducer,
firestore: reduxFirestore,
...reducers,
});
export default function configureStore(): Store {
const store = createStore(
createRootReducer(history), // root reducer with router state
compose(
applyMiddleware(
routerMiddleware(history), // for dispatching history actions
thunk
)
)
);
return store;
}

Update: As confirmed by #luis, the fix was actually importing firestoreReducer instead of reduxFirestore in the configureStore.ts.
You are setting fiterstore as reduxFirestore, which is imported from redux-firestore library which is indeed a function.
I am not sure if you are using it correctly. Following is usage code from library's npm page:
import { createStore, combineReducers, compose } from 'redux';
import { reduxFirestore, firestoreReducer } from 'redux-firestore';
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/database';
import 'firebase/firestore';
const firebaseConfig = {}; // from Firebase Console
const rfConfig = {}; // optional redux-firestore Config Options
// Initialize firebase instance
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);
Notice how createStoreWithFirebase is called instead of createStore and firestoreReducer is passed along with an initial state.

Related

useFirestoreConnect returns empty object in react redux firebase

I am trying to create a todo app using react redux firebase. I have been able to connect the react redux firebase library to firebase as my create task actions produces changes in the firestore. But the redux store does not seem to be connected to firestore which is why I receive an empty object in console.log when i use fireStoreConnect in the useSelector hook.
store.js
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
// Redux
import { applyMiddleware, legacy_createStore as createStore } from 'redux';
import thunk from 'redux-thunk';
import { getFirebase } from 'react-redux-firebase';
import { getFirestore } from 'redux-firestore';
import { createFirestoreInstance } from 'redux-firestore';
// Reducers
import rootReducer from './reducers/rootReducer';
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: 'AIzaSyDOka0NyhrtvdX3hQihX0yVgHQ3m9f6Alg',
authDomain: 'todo-list-720.firebaseapp.com',
projectId: 'todo-list-720',
storageBucket: 'todo-list-720.appspot.com',
messagingSenderId: '770009943120',
appId: '1:770009943120:web:02fbc5adb060ee2cbc9555',
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
// Initialize Firestore
firebase.firestore();
const rrfConfig = {
userProfile: 'users',
useFirestoreForProfile: true,
};
const store = createStore(
rootReducer,
applyMiddleware(thunk.withExtraArgument({ getFirebase, getFirestore }))
);
const rrfProps = {
firebase,
config: rrfConfig,
dispatch: store.dispatch,
createFirestoreInstance,
};
export { store, rrfProps };
Home.js
import { useSelector } from 'react-redux';
import { useFirestoreConnect } from 'react-redux-firebase';
// Components
import Navigation from '../components/Navigation';
import TaskList from '../components/TaskList';
import AddTask from '../components/AddTask';
const Home = () => {
useFirestoreConnect(['tasks']);
const tasks = useSelector((state) => {
console.log(state.firestore);
return state.firestore.data.tasks;
});
return (
<>
<Navigation />
<AddTask />
<TaskList tasks={tasks} />
</>
);
};
export default Home;
rootReducer.js
import { firebaseReducer } from 'react-redux-firebase';
import { firestoreReducer } from 'redux-firestore';
const rootReducer = combineReducers({
firebase: firebaseReducer,
firestore: firestoreReducer,
/* auth: authReducer, */
tasks: tasksReducer,
});
image of firestore collection
CodeSandbox Link

React-router-dom params undefined in nested route after using link

I need a switch component to have access to route params. The switch is rendered in one of the routes but its also rendered outside of it. Is there a way to get the same params in the component rendered outside of the route? Thanks for the help in advance!
It's usually a good pattern to not directly pass params through the route and keep those simple with the view component. You can use useContext, and then have each component(route) plug into that state using the useContext hook in the component.
for example...
app.js
import { useState } from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { Routes } from "./auth/routes.js";
import { GlobalContext } from './globals/GlobalContext.js';
const App = () => {
// variables
const [someState, setSomeState] = useState('hello world');
// render
return (
<div>
<GlobalContext.Provider value={{someState, setSomeState}}>
<Router children={Routes} basename={process.env.REACT_APP_PUBLIC_URL} />
</GlobalContext.Provider>
</div>
);
}
GlobalContext.js
import { createContext } from 'react';
export const GlobalContext = createContext("");
routes.js
import { Route, Switch } from "react-router-dom";
// views
import ViewOne from '../views/ViewOne.js';
import ViewTwo from '../views/ViewTwo.js';
// globals
import { frontendLinks } from '../globals/index.js';
export const Routes = (
<Switch>
<Route exact path={frontendLinks.viewOne} component={ViewOne}></Route>
<Route exact path={frontendLinks.viewTwo} component={ViewTwo}></Route>
</Switch>
);
now the views...
import { useContext } from 'react';
// globals
import { GlobalContext } from '../globals/GlobalContext.js';
const ViewOne = () => {
const { someState } = useContext(GlobalContext);
return (
<div>
<h1>{someState}<h1>
</div>
)
}
export default ViewOne;
and
import { useContext } from 'react';
// globals
import { GlobalContext } from '../globals/GlobalContext.js';
const ViewTwo = () => {
const { someState } = useContext(GlobalContext);
return (
<div>
<h1>{someState}<h1>
</div>
)
}
export default ViewTwo;
If you don't want to manage shared state in your app.js file, I suggest you check out this video for managing useContext state in different files > https://www.youtube.com/watch?v=52W__dKdNnU

Unit Testing to see if JSON file is null

I am currently trying to unit test a container that pulls in a static JSON file of phone numbers and passes it to the component to display, however I am not sure how I should go about testing it. The code for the container is as follows:
import React from 'react';
import data from *JSON file location*
import CountryInfo from *component for the country information* ;
class CountryInfoContainer extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
numbersJson: null
};
}
async componentWillMount() {
const numbersJson = data;
this.setState({ numbersJson });
}
render() {
return (
<CountryInfo json={this.state.numbersJson} showText={this.props.showText} />
);
}
}
export default CountryInfoContainer;
I currently have my unit test to look like this
import React from 'react';
import Adapter from 'enzyme-adapter-react-16';
import { mount, configure } from 'enzyme';
import { MemoryRouter } from 'react-router-dom';
import CountryInfoContainer from './CountryInfoContainer';
configure({ adapter: new Adapter() });
describe('Successful flows', () => {
test('checks if json has null entries', () => {
const wrapper = mount(<MemoryRouter><CountryInfoContainer /></MemoryRouter >);
const data = wrapper.find(numbersJson);
// eslint-disable-next-line no-console
console.log(data.debug);
});
});
Obviously, it doesn't work now because I am not sure how to use the variable numbersJson in the container in the test file or how to check if it is null.
The variable numbersJson is not defined in the scope of your test. If I understand correctly, you are testing that when you first mount the component, that it's state contains a null value for the numbersJson key.
First of all, you need to mount your component directly without MemoryRouter:
const wrapper = mount(<CountryInfoContainer />);
Then you can write an expect() for the state:
expect(wrapper.state().numbersJson).toBeNull();

redux persist in the next js project persist:root is not creating localstorage

using the nextjs framework the redux-persist is not creating the local storage values. After login the persist:root is not showing in the local
In the reactjs framework, I have tried the redux persist the persist:root created in the local storage but in the nextjs framework the same method I am following the errors not coming but the persist:root is not showing
in the local storage
//store.js
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducers from './reducers';
import { persistReducer } from 'redux-persist';
import nextConnectRedux from 'next-connect-redux';
import storage from 'redux-persist/lib/storage/session';
const persistConfig = {
key: "root",
storage: storage,
}
const persistedReducer = persistReducer(persistConfig, reducers)
const middleware = [thunk];
const composeEnhancers =
typeof window !== 'undefined' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
}) : compose;
const enhancer = composeEnhancers(
applyMiddleware(...middleware),
);
const store = () => {
return createStore(
persistedReducer,
{},
enhancer
)};
const nextConnect = nextConnectRedux(store)
export default nextConnect;
// index.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { persistStore } from 'redux-persist';
import nextConnect from '../store';
import Route from '../routes';
import { BrowserRouter } from "react-router-dom";
class App extends Component {
render () {
const persistor = persistStore(nextConnect);
return (
<Provider store={nextConnect}>
<PersistGate loading={null} persistor={persistor}>
<BrowserRouter>
<Route/>
</BrowserRouter>
</PersistGate>
</Provider>
)
}
}
export default App;
I want the persist:root in the local storage to be showed
if you are rendering React on the server, you cant use redux-persist with default configs
When you are using redux-persist with the default configuration, means you are storing your data on browser storage and you don’t have a browser on the server
The following implementation shows you how to integrate Redux Persist into Next.js
rootReducer.js
store.js
_app.js
That's it
resource
Redux Persist with Next.js

React Redux Turbo Module Build Failed

I've been following this tutorial (https://www.turbo360.co/tutorial/redux-walkthrough) and I keep trying to run webpack but the build keeps failing. Any one know why it keeps crashing?
import { createStore, appMiddleware, combineReducers } from 'redux'
import thunk from 'redux-thunk'
import { todoReducer } from './reducers'
let store = null
export default {
createStore: () => {
const reducers = combineReducers({
todo: todoReducer
})
store = createStore(
reducers
appMiddleware(thunk)
)
return store
},
currentStore: () => {
return store
}
}
Does anyone know the solution?
You need to import applyMiddleware, not appMiddleware. It's a typo.
applyMiddleware