I'm using react-redux-firebase and redux-firestore packages.
I'm trying to connect firestore to redux using the useFirestoreConnect hook, but after calling this hook it gives me a TypeError like in this picture.
I've searched in the GitHub issues, docs and here but I'vent fount any solution.
The error: Uncaught (in promise) TypeError: Object(...) is not a function
you see the whole error in this picture:
The console.log error
The TypeError returned
Hello guys I figure out where the problem coming from.
This is for anyone who is looking for a solution.
react-redux-firebase and redux-firestore are having some issues
in versions compatibility, so to skip that I installed the latest
version of the packages!
Clearly there were some differences between old versions and the new
ones of giving your app the redux firebase provider.
The old way might look like this:
const store = createStore(
rootReducer,
composeEnhancers(
reactReduxFirebase(firebase, rrfConfig),
reduxFirestore(firebase),
applyMiddleware(thunk.withExtraArgument({ getFirebase, getFirestore }))
)
);
but if you want to implement hooks in your app and use the useFirestoreConnect this will not work.
In new versions you need to remove the reactReduxFirebase and reduxFirestore from your createStore func and instead use the ReactReduxFirebaseProvider imported from react-redux-firebase and wrap your app inside it, like this:
<ReduxProvider store={store}>
<ReactReduxFirebaseProvider {...rrfProps}>
<BrowserRouter>
<AuthIsLoaded>
<App />
</AuthIsLoaded>
</BrowserRouter>
</ReactReduxFirebaseProvider>
</ReduxProvider>
and passed props: firebase, react-redux-firebase config and any other things you wan. the rrfProps are lik this:
const rrfProps = {
firebase,
config: rrfConfig,
dispatch: store.dispatch,
createFirestoreInstance, //since we are using Firestore
};
and this is the react-redux-firebase config (rrfConfig):
const rrfConfig = {
userProfile: "users",
useFirestoreForProfile: true, // Firestore for Profile instead of Realtime DB
attachAuthIsReady: true, // attaches auth is ready promise to store
};
Related
I have a following question.
I was asked to make example project that compares Redux Toolkit Query and Redux Toolkit with use of Fetch API (or Axios).
I have the Redux Toolkit Query part.
How can I add another store?
Should I do:
<ChosenStoreContext>
<Provider store={store}>
<ApiProvider api={api}>
...Rest of the app
</ApiProvider>
</Provider>
</ChosenStoreContext>
with ChosenStoreContext (useContext boolean value) added just to tell components whether they should dispatch query actions or store actions
Or should I go completely other route?
ApiProvider documentation says that it can cause conflicts.
Any tips would be helpful!
An ApiProvider will also just create a store and use a Provider to pass that down - overwriting the original Provider.
Generally, you should have only one store in your application - and you can have both of those examples on different slices in one store, without them influencing each other.
There is an option of having mutiple different providers and sets of hooks using multiple contexts but that is extra work and will not gain you anything.
Just put everything in the same store.
All you need to do is only add a provider in your App and then in your main store file just add reducer from api Reducer and finally add it's middleware look like this:
// fooSlice.js
const fooReducer = createSlice({
//todo
});
export default fooReducer.reducer
//-->> fooApiSlice.js
const fooApiReducer = createApi({
reducerPath: "tag",
baseQuery: fetchBaseQuery({baseUrl: "path"}),
tagTypes: [tag],
endpoints: (build) => ({
getItems: build.query({
//todo
}),
})
})
export default fooApiReducer
//-->> store.js
import fooReducer from "./fooSlice"
import fooApiReducer from "./fooApiSlice"
export const store = configureStore({
reducer: {
foo: fooReducer,
fooApi: fooApiReducer.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({}).concat([
fooApiReducer.middleware
]),
})
//-->> index.js
<Provider store={store}>
<App/>
</Provider>
I am creating a react app that should connect to Firebase and query Firestore. I am using react-redux-firebase and redux-firestore to connect to the Firebase API. I however get an error indicating that an Object... is not a function. please assist. Below is my code
I import the two like so
import { reduxFirestore, getFirestore } from 'redux-firestore';
import { reactReduxFirebase, getFirebase } from 'react-redux-firebase';
then I import my Firebase config file like so:
import fbConfig from './config/fbConfig';
My store then follows:
const store = createStore(rootReducer,
compose(
applyMiddleware(thunk.withExtraArgument({ getFirebase, getFirestore })),
reduxFirestore(fbConfig),
reactReduxFirebase(fbConfig)
)
);
The affected line is this
applyMiddleware(thunk.withExtraArgument({ getFirebase, getFirestore })),
It says Type error Object is not a Method.
Please assist. Thanks
This error is usually related to the version of the react-redux-firebase that you are importing. Please, run the below command, to check if this fixes your compatibility issues.
npm i --save react-redux-firebase#next
Besides that, as indicated in this other post here and in the official documentation here, you will need to change your code to fits in the needed setting, for it to work.
Your new code should look more like this.
import { ReactReduxFirebaseProvider } from 'react-redux-firebase'
import { createFirestoreInstance } from 'redux-firestore'
const store = createStore(
rootReducer,
initialState,
compose(
)
)
const rrfProps = {
firebase,
config: rrfConfig,
dispatch: store.dispatch,
createFirestoreInstance // <- needed if using firestore
}
const App = () => (
<Provider store={store}>
<ReactReduxFirebaseProvider {...rrfProps}>
<Todos />
</ReactReduxFirebaseProvider>
</Provider>
);
This code is untested, however, it's based in successful cases and the official documentation, so I believe it should help you. I would recommend you to give it a try using it and checking the URLs I linked here, if you want a better understanding of your issue.
Let me know if the information helped you!
I have an Electron desktop application containing a React + Redux app. Redux works fine whilst running the app locally in development, but does not update components once the app has been built to a native desktop app.
Many articles and issues seem to think that the store is configured incorrectly, or that I am mutating state directly rather than updating it, or that my mapStateToProps function is not set up correctly.
I can't see how any of these can be an issue, as my app works during development, and I can see the store be updated and the component re-renders.
In production though, the following happen:
The store state is initialized
An action is dispatched
The state updates ( I can see in the dev tools )
None of my connected components re-render with updated props.
The only difference I can see between development and production is that within Electron, during dev the app is loaded via http://localhost, and during production it is loaded via file:///
My store is configured as:
export const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)));
The store is provided as:
<Provider store={store}>
<App />
</Provider>
I am connecting my component to the store as:
const mapStateToProps = (state: RootState) => {
return {
hasLoaded: state.products.hasLoaded,
products: state.products.products
};
};
const mapDispatchToProps = {
getProducts: getProducts
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(ProductsList);
Then calling getProducts from within the component like:
componentDidMount() {
this.props.getProducts();
}
I expect the state to be updated with the retrieved products, and then the component should re-render with the updated store state as props.
Instead, the store state is updated - as I can see it in Redux DevTools - but the connected component never re-renders, nor does componentDidUpdate get called.
I spent many days with the same feeling and issue that you did. After detecting that in production the subscribe function from redux still worked, but react-redux was unable to connect properly, I tried downgrading and it worked.
Can you try just removing composeWithDevTools?
export const store = createStore(rootReducer, applyMiddleware(thunk));
The example below uses the React application store. It also doesn't work with Redux devtools.
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
I removed this part before production build because it required a browser dev plugin; I hope React Native will be the same.
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
Adding the following to electron-webpack.config.json solved the issue, react-redux has to be whitelisted.
{
"whiteListedModules": ["react-redux"]
}
Using create-react-app
//index.js
...
export const store = createStore(getChange, applyMiddleware(thunk))
//getChange is my reducers name
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
registerServiceWorker();
// Box.js which gets rendered in App.js
import {store} from '../../../index'
...
const renderagain = () => store.getState()
store.subscribe(renderagain)
...
This throws me an error
TypeError: Cannot read property 'subscribe' of undefined
Excuse me? What am I doing wrong?
It's a circular dependency issue.
index.js imports App.js, which eventually imports Box.js. But, Box.js is attempting to import {store} from "../../index.js", which is wrong in several ways.
Your component files should not be attempting to import the store directly, and definitely should not be attempting to import values from index.js. You also shouldn't be trying to subscribe to the store directly in your component files.
Instead, use the React-Redux connect() function in your components to create wrappers that manage the process of subscribing to the store for you. Then, use the connected components, and they'll automatically use the store you passed to <Provider>.
//index.js
...
export const store = createStore(getChange, applyMiddleware(thunk))
//getChange is my reducers name
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
registerServiceWorker();
the code above is good to be used to create a store with some reducers combined. and also providing that tot he whole application by passing it into the Provider Component wrapping the Application. This makes the redux actions and store contents available to access for the component. There you can subscribe the store to et notified on changes in store, or on action dispatches.
You are using the callback to subscribe in a wrong way. You might use it this way:
function select(state) {
return state.some.deep.property
}
let currentValue
function handleChange() {
let previousValue = currentValue
currentValue = select(store.getState())
if (previousValue !== currentValue) {
console.log(
'Some deep nested property changed from',
previousValue,
'to',
currentValue
)
}
}
const unsubscribe = store.subscribe(handleChange)
unsubscribe()
For further documentation and queries you can see this. https://redux.js.org/api/store#subscribe-listener
First of all, I'm a beginner in React & Redux.
I'm trying to get components from one project to another. I made one project a npm package, so i can import directly from this project. The problem is that I'm using a store in my main project and my npm package uses a store as well. This results in states being undefined because I only give one store with the provider.
this is the index.js from my main project, I know you can't have 2 Providers, but I wanted to point out that I'm searching to have the functionality of both stores:
import { guiReducer, intlInitialState } from 'second-project';
const secondStore = createStore(guiReducer, intlInitialState);
const store = configureStore();
render(
<Provider store={store}>
<Provider store={secondStore}
<Router>
<App />
</Router>
</Provider>
</Provider>
This is the configureStore.js:
import rootReducer from '../reducers';
function configureStoreProd(initialState){
return createStore(
rootReducer,
initialState,
applyMiddleware(thunk)
);
}
const configureStore =
process.env.NODE_ENV === 'production' ? configureStoreProd : configureStoreDev;
export default configureStore;
rootReducer is a combined reducer from the main project and guiReducer is a combined reducer from the second project.
Sample code for rootReducer (similar for guiReducer):
const appReducer = combineReducers({
loggedIn,
courses,
lessons,
organisation,
});
const rootReducer = (state,action) => {
if (action.type === LOGOUT) {
state = initialState;
}
return appReducer(state,action);
};
export default rootReducer;
I also tried to combine both root/gui-reducers and making a new store like this (configureStore.js) :
function configureCombinedStoreProd(initialState){
return createStore(
combineReducers({
rootReducer,
guiReducer,
}), initialState, applyMiddleware(thunk)
);
}
const configureCombinedStore =
process.env.NODE_ENV === 'production' ? configureCombinedStoreProd :
configureCombinedStoreDev;
export {configureCombinedStore as configureCombinedStore };
Thanks in advance.
I'd suggest you to avoid saving another store in the npm package. Instead, wrap only the components you need inside the npm package, make them accept properties different than "store", and copy the old project's reducers inside your "reducers" folder. Instead, if you use the "duck pattern", you may want to save the old reducers in the npm package as well (only the reducers, not the store!) and import them in your store when you call something like combineReducers inside your new store.js file.
I have currently solved this by wrapping the components in App.js with a
<Provider store={store}>
from the second project while in index.js "App" is wrapped with the provider from the main project.