React Redux - Error passing several store enhancers to createStore() - node.js

I have a react app running redux and thunk which has all been working fine. I need to persist the store state on page reload so that data is not lost, so have created a function which is storing data in the localstorage and then returning the data ready for adding to createStore (https://stackoverflow.com/a/45857898/801861). The data storage is working fine and returning the object ready for setting the sate. When adding the data object at createStore react fails to compile with this error:
Error: It looks like you are passing several store enhancers to createStore(). This is not supported. Instead, compose them together to a single function
Here is CURRENT CODE RETURNING ERROR:
const store = createStore(reducers, LoadState, applyMiddleware(thunk) );
//Error: It looks like you are passing several store enhancers to createStore(). This is not supported. Instead, compose them together to a single function
My original code which was running:
const store = createStore(reducers, applyMiddleware(thunk) );
I attempted to fix this following some similar issues I found online, compiles but breaks site code which was originally working fine:
const composeEnhancers = LoadState || compose;
const store = createStore(reducers, composeEnhancers( applyMiddleware(thunk) ) );
//Error: Actions must be plain objects. Use custom middleware for async actions.
Not sure what I need to change to get this to work, any help is appreciated.

I think you are following a tutorial which is performing tasks in a previous version of redux.
You need to create a composeEnhancer which will take in your Redux Dev Tools extension as shown
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
after importing compose from 'redux' obviously as shown -
import {createStore, compose, applyMiddleware} from 'redux';
and then, you can create the store as shown -
const Store = createStore(rootReducer, composeEnhancer(applyMiddleware(thunk)))

The error is self-explanatory. It tells you what to do exactly!!
Namely it tell you that you should compose your enhancers instead.
Here is how to it:
Step #1: Import 'compose' from redux library
import { createStore, applyMiddleware, compose } from 'redux';
Step #2: Compose your list of enhancers since you have more than one
const enhancers = [LoadState, applyMiddleware(thunk)];
const store = createStore(
reducers,
compose(...enhancers)
);
Refer to this page for more details.

I suspect your issue is within your LoadState. What ever is it? Here is a working createStore:
const store = createStore(
reducers,
{ counter: { count: 5 } },
applyMiddleware(() => dispatch => {
console.log('Yoyoyo')
return dispatch;
}));
Hope it solves your issue. Make sure to put actual initial state values and not some function or what ever it is LoadState is :)

You can use a package to persist the redux store into the local storage and you don't need to make your own function:
https://github.com/rt2zz/redux-persist
In the first example of the package you can see how to use the persistReducer() and persistStore() to save your state and then auto rehydrates on refresh page.

plz check this advanced store setup that may help you
enter link description here
https://github.com/zalmoxisus/redux-devtools-extension#12-advanced-store-setup
import { createStore, applyMiddleware, compose } from 'redux';
+ const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
+ const store = createStore(reducer, /* preloadedState, */ composeEnhancers(
- const store = createStore(reducer, /* preloadedState, */ compose(
applyMiddleware(...middleware)
));

Am starting out with it React-Redux and faced the same issue. am not sure if it is the right approach but here we go.
the one issue you only need to fix in your code is to call the function,
store = createStore(reducers, LoadState(), applyMiddleware(thunk) );
this solution worked for me.

For redux saga users,
import createSagaMiddleware from "redux-saga";
const sagaMiddleware = createSagaMiddleware();
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(rootReducer, composeEnhancer(applyMiddleware(sagaMiddleware)))

import { applyMiddleware, compose, createStore } from "redux";
import { devToolsEnhancer } from "redux-devtools-extension";
import { logger } from "./middlewares/logger";
import reducers from "./reducers";
import { todoReducer } from "./todoReducer";
const store = createStore(
reducers,
compose(applyMiddleware(logger), devToolsEnhancer({ trace: true }))
);
export default store;

Related

Use TypeORM repository or method on a service from outside any module

I have a nestjs app that has an AuthService which has these parts:
export class AuthService {
constructor(
#InjectRepository(User)
private readonly userRepo: Repository<User>,
) {}
async updateFromInternally () {
...
}
I have another file which is, crucially, outside of any module, which contains a number of helpful functions relating to Google oauth. For example, this file initiates Google's oauth2 client like so:
export const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
process.env.GOOGLE_CLIENT_REDIRECT
);
This file also has a listener function which I found in Google's documentation as a way to catch when my use of Google's oauth2 client automatically uses a refresh token to obtain a new access token:
oauth2Client.on('tokens', async (tokens) => {
[****]
})
At [****], I need to query in my database for a particular user and update them. Either of these conceptually work:
I somehow get userRepo into this file right here and use it to query + update
I somehow call updateFromInternally in AuthService from here
But I don't know how to interact with either TypeORM repositories or methods within services from outside of any module in nestjs! Can I do either of these?
The first question is why you're using nestjs?
You can access the internals of nestjs by using the instantiated app;
In your main.ts file you have something like this:
const app = await NestFactory.create(AppModule);
You can access the services or DataSource from the app by using the get method.
import {DataSource} from 'typeorm'
const dataSource = app.get<DataSource>(DataSource)
// or custom service
const someServices = app.get<SomeService>(SomeService)
you just need a way to export app from main.ts and import it in your outside world.
for example:
// main.ts
let app;
async bootstrap() {
app = await NestFactory.create(AppModule);
}
export const getApp = () => app;
bootstrap()
and in your other file
// outside.ts
import {getApp} from './main.ts'
const app = getApp()
I didn't write the whole logic, but I think it would give you an idea of what you need to do.
But in my opinion, it's the worst thing you can do. You're using 'nestjs` and try to respect its philosophy.
Just write a module that handles all the work you want.
I figured out #1:
import {getRepository} from "typeorm";
oauth2Client.on('tokens', async (tokens) => {
const gaRepo = getRepository(Googleauth);
// Can now use gaRepo like you do in a service
})

How can I add redux-saga to my web extension?

I am working on a project that creates a google chrome extension. I am trying to add redux-saga middleware for using saga debounce. However, I am getting an error that says: Argument type is not assignable of type 'Store<any, AnyAction>'. How can I fix that and How should I do that? There are not various example in the internet in web extension with middleware. Thanks for your time. Here is my code:
in background.ts
const middleware = [saga]
const store = createStore(reducer, initialState)
// a normal Redux store
const storeWithMiddleware = applyMiddleware(store, ...middleware)
wrapStore(storeWithMiddleware, { portName: 'bla' })
in popup.tsx
const store = new Store({ portName: 'bla' })
// wait for the store to connect to the background page
store
.ready()
.then(() => {
// The store implements the same interface as Redux's store
// so you can use tools like `react-redux` no problem!
const root = document.createElement('div')
document.body.appendChild(root)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
root
)
})
.catch((e) => console.log(e))
//});
export default store
applyMiddleware should contain only middlewares (not the store) and be passed as an argument to the createStore function:
const middleware = [saga]
const store = createStore(reducer, initialState, applyMiddleware(...middleware))
const storeWithMiddleware = wrapStore(store, { portName: 'bla' })
Edit:
Since you are using webext-redux, it seems you are actually mixing two ways of creating store together. You should use the applyMiddleware from webext-redux only if you are directly using the proxy Store from webext-redux as well. Since you are using createStore form redux package instead, you should also import the applyMiddleware function from the redux store.
import {createStore, applyMiddleware} from 'redux'
...

Firebase getAuth() throws error getProvider of undefined but can access database

I have the following code running on a Node server.
import admin from 'firebase-admin';
import {getAuth} from 'firebase/auth';
class MyFirebase {
constructor() {
console.log("MyFirebase Constructor");
this.firebaseApp = admin.initializeApp({
credential: admin.credential.cert("PATH_TO_CERT/cert.json"),
databaseURL: "https://DATABASE_URL",
});
console.log("App name="+firebaseApp.name);
this.defaultAuth = getAuth(firebaseApp);
this.database = this.firebaseApp.database();
// database ref code here...
}
}
and it throws the following error:
return app.container.getProvider(name);
TypeError: Cannot read property 'getProvider' of undefined
If I remove "firebaseApp" from the getAuth(..) call I get this error:
No Firebase app '[DEFAULT'] has been created - call Firebase
App.initializeApp() (app/no-app)
However the "console.log("App Name...")" line produces:
App name=[DEFAULT]
So clearly a DEFAULT app has been created. Additionally if I remove the "getAuth..." call the database calls pulling data from the realtime database below it work just fine, which seem to imply the authentication worked properly because I can access data from the database.
What the heck is going on?
You are confusing Firebase Admin SDK (Node.js) with Firebase Javascript SDK. The former is for the back-end, while the latter is for the front-end. I understand your confusion because the front-end package/s are installable via NPM, although they are meant to be bundled with front-end code.
You can't do this:
import admin from 'firebase-admin' // back-end code
import { getAuth } from 'firebase/auth' // front-end code !!!
const adminApp = admin.initializeApp(...)
getAuth(adminApp) // TypeScript actually catches this error
/*
Argument of type 'App' is not assignable to parameter of type 'FirebaseApp'.
Property 'automaticDataCollectionEnabled' is missing in type 'App' but required in type 'FirebaseApp'.ts(2345)
app-public.d.ts(92, 5): 'automaticDataCollectionEnabled' is declared here.
const adminApp: admin.app.App
*/
If you are on the back-end, just use adminApp.auth() to get the Auth instance. If on the front-end, you need to call getAuth with the front-end Firebase App instance:
import { initializeApp } from 'firebase/app'
import { getAuth } from 'firebase/auth'
const app = initializeApp(...)
const auth = getAuth(app)
The new modular apis have a slightly different syntax. The following should still work if you wrap it in a class, but as long as you only do this once at the top of your express? server you shouldn't need to use a class.
Also, I'm using the require syntax but imports should work too depending on your setup.
//Import each function from the correct module.
const { initializeApp, applicationDefault } = require("firebase-admin/app");
const { getAuth } = require("firebase-admin/auth");
const { getDatabase } = require("firebase-admin/database");
const app = initializeApp({
credential: applicationDefault(), //Don't forget to export your configuration json https://firebase.google.com/docs/admin/setup
databaseURL: "https://DATABASE_URL",
});
const auth = getAuth(app)
const database = getDatabase(app)
It's not super well documented but you can find hints in the Admin SDK reference: https://firebase.google.com/docs/reference/admin/node/firebase-admin.auth
One tip: In VSCode you should see the a description of each function when you hover over them, if you have the import path formatted correctly.

How to use i18next in serverless node js?

I am using Node JS Azure functions. I am trying to internationalize the error messages returned by the functions with i18next. I could find examples with express or plain node server. In these cases middleware pattern can be used.
But for functions, I need a way to call i18next.t('key') with probably a language parameter which I am not able to find. Calling i18next.changeLanguage() before every call to i18next.t('key') doesn't seem practical.
My skeleton code is as follows
const i18next = require("i18next");
const backend = require("i18next-node-fs-backend");
const options = {
// path where resources get loaded from
loadPath: '../locales/{{lng}}/{{ns}}.json',
// path to post missing resources
addPath: '../locales/{{lng}}/{{ns}}.missing.json',
// jsonIndent to use when storing json files
jsonIndent: 4
};
i18next.use(backend).init(options);
exports.getString = (key, lang) => {
//i18next.changeLanguage(lang,
return i18next.t(key);
}
It is possible to fetch translations without doing changeLanguage each time?
As pointed out in the comments you need to call the i18next.changeLanguage(lang) function whenever the language needs to be defined or changed.
You can take a look to the documentation here.
The code could look like this
const i18next = require('i18next')
const backend = require('i18next-node-fs-backend')
const options = {
// path where resources get loaded from
loadPath: '../locales/{{lng}}/{{ns}}.json',
// path to post missing resources
addPath: '../locales/{{lng}}/{{ns}}.missing.json',
// jsonIndent to use when storing json files
jsonIndent: 4
}
i18next.use(backend).init(options)
exports.getString = (key, lang) => {
return i18next
.changeLanguage(lang)
.then((t) => {
t(key) // -> same as i18next.t
})
}

Router is not defined in KOA2

I have two files, one of them is the app.js and the otherone is api.js.
In the first file I have :
app.use(setHeader)
app.use(api.routes())
app.use(api.allowedMethods())
And in api.js I have:
import KoaRouter from 'koa-router';
const api = new Router();
//Validatekey
const validateKey = async (ctx, next) => {
const { authorization } = ctx.request.headers;
console.log(authorization);
if (authorization !== ctx.state.authorizationHeader) {
return ctx.throw(401);
}
await next();
}
api.get('/pets', validateKey, pets.list);
When I run the project a error message is throw: Router is not defined.
But If I write both files together, the application go fine.
Anybody knows the problem?
I have solved with var Router = require('koa-router')
The import is currently not implemented in nodejs, neither is it supported in the latest ES2015(ES6).
You will need to use a transpiler like Babel to use import in code.I advice that avoid transpiler as it cause performance issues on production just go with require and it will work.
Obviously Nodejs does not support import / export syntax and using require will solve your problem.
However it is possible to make import work on Node.js by using babel transformers.
Look the following answer for more information https://stackoverflow.com/a/37601577/972240

Resources