Require cycle: App.tsx -> Store/Reducers/Projects.js -> Store/Actions/Projects.js -> App.tsx - firebase

Require cycle: App.tsx -> Store/Reducers/Projects.js -> Store/Actions/Projects.js -> App.tsx
Require cycles are allowed, but can result in uninitialized values. Consider refactoring to remove the need for a cycle.
at node_modules/metro-runtime/src/polyfills/require.js:117:6 in metroRequire
at http://192.168.1.6:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&strict=false&minify=false:177107:24 in <unknown>
at node_modules/metro-runtime/src/polyfills/require.js:349:11 in loadModuleImplementation
at node_modules/redux-thunk/lib/index.js:18:6 in <anonymous>
at node_modules/metro-runtime/src/polyfills/require.js:349:11 in loadModuleImplementation
at http://192.168.1.6:19000/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&strict=false&minify=false:117971:52 in <unknown>
at node_modules/metro-runtime/src/polyfills/require.js:349:11 in loadModuleImplementation
at node_modules/expo/AppEntry.js:3:0 in <global>
- ... 4 more stack frames from framework internals
I think My problem is with the way, I am initialising and exporting firestore and firebase realtime database.
when my app starts it reaches App.tsx and from their it goes to Store/Reducers/Projects.js to initialise and fetch the redux-store from their it goes to Store/Actions/Projects.js to dispatch the actions.
now the problem here is in Store/Actions/Projects.js it imports firestore and realtime database from App.tsx. Because of this I think it's causing Cycle. Am i correct? can any one please help me out and refactor it so that the cycle brakes.
here In App.tsx I first initiate firebase, firestore and realtime database.
const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
export const RealtimeDB = getDatabase(app);
and in Store/Actions/Projects.js I am importing it as
import { db, RealtimeDB } from "../../App";
I assume the problem is in the way I initialise firebase and export it. And I also think there is a problem with import statements. Whole code is provided below.
my App.tsx code
import { useEffect, useState } from "react";
import { StatusBar } from "expo-status-bar";
import { SafeAreaProvider } from "react-native-safe-area-context";
//import { useColorScheme } from "react-native-appearance";
import useCachedResources from "./hooks/useCachedResources";
import useColorScheme from "./hooks/useColorScheme";
import Navigation from "./navigation";
import { ThemeProvider } from "react-native-elements";
// redux imports
import { createStore, combineReducers, applyMiddleware } from "redux";
import { Provider } from "react-redux";
import ReduxThunk from "redux-thunk";
import Allprojects from "./Store/Reducers/Projects";
//firebase config
**import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getDatabase } from "firebase/database";
import { getAuth, onAuthStateChanged } from "firebase/auth";
import AuthScreen from "./screens/AuthenticatonScreens/AuthScreen";**
const firebaseConfig = {****};
**const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
export const RealtimeDB = getDatabase(app);**
const RootReducers = combineReducers({
Projects: Allprojects,
});
const store = createStore(RootReducers, applyMiddleware(ReduxThunk));
export default function App() {
const [isSigned, setisSigned] = useState(false);
const [isLoding, setisLoding] = useState(false);
const isLoadingComplete = useCachedResources();
const colorScheme = useColorScheme();
const auth = getAuth();
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (user) {
const uid = user.uid;
setisSigned(true);
} else {
setisSigned(false);
}
});
});
if (!isLoadingComplete) {
return null;
} else {
return (
<Provider store={store}>
<SafeAreaProvider>
<ThemeProvider useDark={colorScheme === "dark"}>
{isSigned == false ? (
<AuthScreen />
) : (
<Navigation colorScheme={colorScheme} />
)}
<StatusBar />
</ThemeProvider>
</SafeAreaProvider>
</Provider>
);
}
}
my Store/Reducers/Projects.js file
import {
RETRIVING_PROJECT,
RETRIVING_PROJECT_TASKS,
} from "../Actions/Projects";
const initialstate = {
ProjectsInvoledIn: [],
ProjectTasks: [],
};
export default (state = initialstate, action) => {
switch (action.type) {
case RETRIVING_PROJECT:
return {
...state,
ProjectsInvoledIn: action.payload,
};
case RETRIVING_PROJECT_TASKS:
return { ...state, ProjectTasks: action.payload };
}
return state;
};
my Store/Actions/Projects.js file
export const RETRIVING_PROJECT = "RETRIVING_PROJECT";
import { db, RealtimeDB } from "../../App";
import {
writeBatch,
doc,
onSnapshot,
query,
orderBy,
serverTimestamp,
addDoc,
collection,
} from "firebase/firestore";
import {
ref,
set,
onValue,
push,
serverTimestamp as DbSer,
} from "firebase/database";
import { UserIds } from "../../UserIds";
import { getAuth } from "firebase/auth";
import { nanoid } from "nanoid/non-secure";
// CREATING PROJECTS
export const CreateProject = () => { ....my writing and fetching data functions... }

You can put those firebase related functions in different file, then import from that file instead of app.js.

Related

React-redux Toolkit: Cannot set new state, when passing reducer as prop to another function

I am trying to use react redux toolkit and pass setter function to set new state on firebase's 'onAuthStateChanged'. The plan was to pass user's state (object or null) to reducer, depending if user is logged in or logged out. This is my first usage of redux, so I can't get why my code doesn't work. There is no errors, but in redux devtools state is always equal to null.
Configure Store:
import { configureStore } from '#reduxjs/toolkit'
import { Provider } from 'react-redux';
import userReducer from './utils/userReducer';
const store = configureStore({
reducer: {
user: userReducer,
}
})
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
My reducer:
import { createSlice } from "#reduxjs/toolkit";
export const userSlice = createSlice({
name: 'user',
initialState: null,
reducers: {
setUser: (state, action) => {
state = action.payload;
}
}
})
export const {setUser} = userSlice.actions;
export default userSlice.reducer;
Where I am dispatching it:
import { setUser } from '../utils/userReducer'
import { useDispatch } from 'react-redux'
const dispatch = useDispatch()
const handleLogin = async (e) => {
e.preventDefault()
const { user } = await logInWithEmail(email, password)
await setCurrentUser(() => dispatch(setUser))
}
Firebase function, where I am trying to use reducer:
export const setCurrentUser = async (setUser) => {
await onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser)
})
}
I understand, that with useContext it would be much easier, but I am trying to learn redux by implying it.
Try like that:
import { setUser } from '../utils/userReducer'
import { useDispatch } from 'react-redux'
const dispatch = useDispatch()
const handleLogin = async (e) => {
e.preventDefault()
const { user } = await logInWithEmail(email, password)
// This line updated
await setCurrentUser((currentUser) => dispatch(setUser(currentUser)))
}
The reason:
your setCurrentUser function prop setUser is just function () => dispatch(setUser), but this function does not receive any prop, and dispatch(setUser) does not do anything. you need to pass value (payload) to reducer function.
Additionally, try passing dispatch itself as prop and dispatch inside of onAuthStateChanged.
export const setCurrentUser = async (dispatch) => {
await onAuthStateChanged(auth, (currentUser) => {
dispatch(setUser(currentUser))
})
}
import setUser reducer function if handleLogin and setCurrentUser function is in different files separately.

Migrating from Vite with ReactJS to Nexjs, SyntaxError: Cannot use import statement outside a module

I am migrating a vite and react project to Nextjs. This project uses redux-persist.
When migrating and running code it shows this error.
I was trying several solutions found on the net but none helped.
I created a new NextJS project from scratch and ended with the same error.
import { FLUSH, PAUSE, PERSIST, PURGE, REHYDRATE, DEFAULT_VERSION } from './constants';
SyntaxError: Cannot use import statement outside a module
My _app.tsx code
import { persistor, store } from "app/store";
import { Provider } from "react-redux";
function MyApp({ Component, pageProps }: AppProps) {
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
}
export default MyApp;
app/store.ts
import { configureStore, combineReducers } from "#reduxjs/toolkit";
import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from "redux-persist";
import storage from "redux-persist/lib/storage";
import logger from "redux-logger";
import rootReducers from "./rootReducers";
const isDev = process.env.NODE_ENV === "development";
const persistConfig = {
key: "root",
version: 1,
storage,
whitelist: ["darkmode"],
};
const rootReducer = combineReducers(rootReducers);
const persistedReducer = persistReducer(persistConfig, rootReducer);
const middlewareLogger: any = !!isDev ? logger : [];
export const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}).concat(middlewareLogger),
});
export let persistor = persistStore(store);
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
Someone got it to work with NextJS?
Thanks!

How can I upload image to firebase storage without 2 ref imports colliding? [duplicate]

I want to upload an image to firebase storage, version 9. I have working code for the firestore, but I cant for the life of me understand the firebase docs regarding uploading, and how to make it work for Vue (which also requires the import of a REF function).
my question is: How do I import the ref function in Vue and also import and use the ref function from firebase firestore?
This is what I have. It feels wrong to wrap the Firebase ref with a .value, but I just put it in there to get past the vue error.
vue component code fragment: <-- this works
if (imageFile.value) {
await uploadImage(imageFile.value);
console.log("image:" + url.value);
}
useStorage.js <--this is where everything breaks down trying to convert from Firebase 8 to 9. Is it the vue Ref function?
import { ref } from "vue";
import { projectStorage } from "../firebase/config";
import { uploadBytesResumable, getDownloadURL } from
"#firebase/storage";
const useStorage = () => {
const error = ref(null);
const url = ref(null);
const filePath = ref(null);
//I need to use ref with firestore here
const uploadImage = async (file) => {
filePath.value = `images/${file.name}`;
const storageRef = ref(projectStorage,
filePath.value).value;
try {
const res = await storageRef.put(file);
url.value = res.ref.getDownloadURL();
} catch (err) {
console.log(err.message);
error.value = err.message;
}
};
return { url, filePath, error, uploadImage };
};
export default useStorage;
config.js
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getStorage } from "firebase/storage";
import { getAuth } from "firebase/auth";
const firebaseConfig = {
[info]
};
// init firebase
const firebaseApp = initializeApp(firebaseConfig);
// init firestore service
const db = getFirestore(firebaseApp);
// init firestore authorization
const auth = getAuth(firebaseApp);
const projectStorage = getStorage(firebaseApp);
export { db, projectStorage, auth };
You can set an alias for either of the imports as shown below:
import { ref } from "vue";
import { projectStorage } from "../firebase/config";
import { ref as storageRef } from "#firebase/storage";
const fileRef = storageRef(projectStorage, filePath.value);
// use storageRef here ^^^ instead of ref from vue
Also checkout: How to import two classes by the same name in javascript/es6?

setup saga middleware with redux-starter-kit's configureStore()

I am working on the application which is purely redux-saga, but as the application is growing, the number of files is also growing. To solve this issue I am trying to setup redux-starter-kit to my current application.
Here is my store configuration file index.js
import { configureStore, getDefaultMiddleware } from 'redux-starter-kit'
import rootReducer from '../reducers'
export const store = configureStore({
reducer: rootReducer,
middleware: [...getDefaultMiddleware()]
})
old set up for just redux-saga without redux-starter-kit
// import createSagaMiddleware from 'redux-saga'
// import { initSagas } from '../initSagas'
// import rootReducer from '../reducers'
// import { loadState, saveState } from './browserStorage'
// function configureStore () {
// const sagaMiddleware = createSagaMiddleware()
// const persistedState = loadState()
// const createdStore = createStore(
// rootReducer,
// persistedState,
// applyMiddleware(sagaMiddleware)
// )
// initSagas(sagaMiddleware)
// return createdStore
// }
// export const store = configureStore()
// store.subscribe(() => {
// saveState(store.getState())
// })
the problem:
when I set up the redux-starter-kit the old sagas are not working.
Long story short:
How can I set up my existing redux-saga application with redux-starter-kit, without disturbing the current saga files?
Thank you in advance.
redux-starter-kit does not include sagaMiddleware by default [1]. You'll need to add it to the middleware list and initialize the sagas yourself.
In your case I believe this should work:
import createSagaMiddleware from 'redux-saga'
import { configureStore, getDefaultMiddleware } from 'redux-starter-kit'
import rootReducer from '../reducers'
import { initSagas } from '../initSagas'
const sagaMiddleware = createSagaMiddleware();
export const store = configureStore({
reducer: rootReducer,
middleware: [...getDefaultMiddleware(), sagaMiddleware]
})
initSagas(sagaMiddleware);
[1] https://redux-starter-kit.js.org/api/getdefaultmiddleware

React native persist and encrypt user token - Redux-persist-transform-encrypt error

It seems there is an issue using the encrypt option of redux-persist in react-native:
https://github.com/maxdeviant/redux-persist-transform-encrypt/issues/15
Can anyone help with any solution/workaround to use redux persist to encrypt and store a login token in react-native?
When I try to use the redux persist with the redux-persist-transform-encrypt i get
Redux-persist-transform-encrypt: expected outbound state to be a string error
import { createStore, compose, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk';
import { persistStore, autoRehydrate } from 'redux-persist';
import { AsyncStorage } from 'react-native';
import createEncryptor from 'redux-persist-transform-encrypt';
import reducers from './reducers';
const store = createStore(
reducers,
{},
compose(
applyMiddleware(ReduxThunk),
autoRehydrate(),
),
);
const encryptor = createEncryptor({
secretKey: 'my-super-secret-key-999',
});
persistStore(
store,
{
storage: AsyncStorage,
whitelist: ['auth'],
transforms: [encryptor],
},
);
export default store;
My auth state is something like this:
const INITIAL_STATE = {
user: null,
token: ''
};
Is there any solution to use redux-persist-transform encrypt or the transform and other package to encrypt the token when using redux persist?
I found a solution using the customTransform instead of redux-persist-transform-encrypt:
import { createStore, compose, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk';
import { persistStore, createTransform, autoRehydrate } from 'redux-persist';
import { AsyncStorage } from 'react-native';
import CryptoJS from 'crypto-js';
import reducers from './reducers';
const store = createStore(
reducers,
{},
compose(
applyMiddleware(ReduxThunk),
autoRehydrate(),
),
);
const encrypt = createTransform(
(inboundState, key) => {
if (!inboundState) return inboundState;
const cryptedText = CryptoJS.AES.encrypt(JSON.stringify(inboundState), 'secret key 123');
return cryptedText.toString();
},
(outboundState, key) => {
if (!outboundState) return outboundState;
const bytes = CryptoJS.AES.decrypt(outboundState, 'secret key 123');
const decrypted = bytes.toString(CryptoJS.enc.Utf8);
return JSON.parse(decrypted);
},
);
persistStore(
store,
{
storage: AsyncStorage,
whitelist: ['auth'], // <-- keys from state that should be persisted
transforms: [encrypt],
},
);
export default store;
When using redux-persist initial state is triggered before rehydrating is finished so I had to apply this too:
https://github.com/rt2zz/redux-persist/blob/master/docs/recipes.md#delay-render-until-rehydration-complete
This worked for me:
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import createEncryptor from 'redux-persist-transform-encrypt';
import storage from 'redux-persist/lib/storage';
import rootReducer from '/path/to/your/rootReducer';
const encryptor = createEncryptor({
secretKey: 'omg-this-is-some-secret-stuff',
});
const persistConfig = {
key: 'root',
storage,
transforms: [encryptor],
};
const reducer = persistReducer(persistConfig, rootReducer);
export const store = createStore(reducer);
export const persistor = persistStore(store);
This is working fine and store data in session storage.
Use below to encript redux data.
1) install redux-persist-transform-encrypt module
yarn add redux-persist-transform-encrypt
npm install redux-persist-transform-encrypt --save
2) import redux files.
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import createEncryptor from 'redux-persist-transform-encrypt';
import storageSession from 'redux-persist/lib/storage/session';// store data in session storage
// import storage from 'redux-persist/lib/storage'; // store data in local storage
import promise from 'redux-promise';
import rootReducer from './path/reducers/';
const encryptor = createEncryptor({
secretKey: 'test#key12',
});
const persistConfig = {
key: 'root',
storage:storageSession,
// storage:storage,
transforms: [encryptor],
}
const persistedReducer = persistReducer(persistConfig, rootReducer)
export default () => {
let store = createStore(persistedReducer)
let persistor = persistStore(store)
return { store, persistor }
}

Resources