Combining 2 redux stores from 2 different projects - reactjs

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.

Related

useSelector and dispatch using persist redux

I am using persist redux to save the state of some states after refresh.
However, I'm having trouble accessing the values using these tools.
For example, using a simple redux toolkit I can simply do:
const userId = useSelector((state) => state)
However, when using a persist reducer, it returns undefined.
Here's my code for store:
import { configureStore } from '#reduxjs/toolkit';
import idReducer from './idSlice'
import { persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage' // defaults to localStorage for web
import thunk from 'redux-thunk'
const persistConfig = {
key: 'root',
storage,
}
const persistedReducer = persistReducer(persistConfig, idReducer)
let store = configureStore({
reducer: persistedReducer,
devTools: process.env.NODE_ENV !== 'production',
middleware: [thunk]
});
export default store;
index.js:
const root = ReactDOM.createRoot(document.getElementById("root"));
let persistor = persistStore(store)
root.render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>
);
Here's what I have for dispatch (doesn't seem to work either)
const handleClick = (id) => {
console.log("dispatch ", id)
dispatch(setId(id))
}
Thanks!
You said
I am using persist redux to save the state of some states after refresh.
Redux does not keep anything after refresh. Its store lives in JavaScript, so when the code is triggered to run again, everything restarts.
The first important thing is to consider not refreshing at all. I mean keep a high order component, and re-render the components below it.
The second way is to save the necessary values on localStorage, or sessionStorage (the difference is that while data in localStorage doesn't expire, data in sessionStorage is cleared when the page session ends, found here) or on your database on the backend.
Normally user's data (not risky data, like token) is saved on localStorage so user wouldn't have to sign in every time.

Can we use store from different libraries together in react project?

Right now we are using easy peasy in our project, now we want to remove easy peasy store gradually and replace it with reduxtoolkit. Can we use stores with different libraries in react? Or is any alternative way to deal with this situation.
Tried below which is not working:
**Creating store out of reduxtoolkit**
import { configureStore,combineReducers } from "#reduxjs/toolkit";
import appReducer from "./slice/appReducer";
const rootReducer= combineReducers({
app: appReducer,
});
const store = configureStore({
reducer: rootReducer,
});
**For easy peasy**
import models from './models';
import { createStore } from 'easy-peasy';
const store = createStore(models);
**In main file**
<Provider store={store }>
<Provider store={reduxStore }>
<App/>
</Provider>
</Provider>
**It is failing with Error:**
easy-peasy.esm.js:93 Uncaught TypeError: store.getActions is not a function
Basically Missing step from my side was Importing Provider from correct package.
import { Provider as ReduxProvider } from "react-redux";
import { StoreProvider as Provider } from 'easy-peasy';
<ReduxProvider store={reduxStore }>
<Provider store={easyPeasystore }>
Changing my code with above line helped me in solving problem.

Accessing firebase API using redux in React

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!

How to enable Redux Devtools?

I am following tutorial on React and instructor install an extension on Chrome, the Redux Devtools. In my case i am wondering why my extension seems to be inactive (in color gray). In my chrome extension settings, it is On, site access is set On all sites, Allow access to file URLs
is on but when i view my Redux tab, it shows:
No store found. Make sure to follow the instructions.
On the .js file, there is a declaration something like this:
const ReactReduxDevTools = window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__();
let store;
if(window.navigator.userAgent.includes("Chrome") && ReactReduxDevTools){
store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
ReactReduxDevTools)
);
}else{
...
}
What could be the problem? Compatibility with the Chrome?
import {Provider} from 'react-redux'
import {createStore, applyMiddleware, compose} from 'redux'
import reducers from './reducers';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducers, composeEnhancers(applyMiddleware()))
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
It only works when it detects a store on the application you are running. It makes sense since there is nothing to be shown.
Start an application with Redux correctly wired up and it will appear colored and will have very useful information.
EDIT:
I think I found it. Check the code correction. The compose method must be raplace if a __REDUX_DEVTOOLS_EXTENSION_COMPOSE__ exists.
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
let store;
store = createStore(
rootReducer,
initialState,
composeEnhancers(
applyMiddleware(...middleware)
);
No if statements
The easier way to apply if you have multiple middlewares.
Install extension using npm or yarn
npm install --save redux-devtools-extension
Apply to store.js or wherever your store is initialized
import { composeWithDevTools } from 'redux-devtools-extension';
const middlewares = [] //put your middleware over here
export const store = createStore(Reducer,composeWithDevTools(
applyMiddleware(...middlewares))
);

react-redux can't find store but it sure looks like it's there

OK - what the heck am I missing... spent a day and a half trying to solve this and am about to ditch redux...
I have the following root route...
...
import configureStore from 'NewApp/client/store';
import createBrowserHistory from 'history/lib/createBrowserHistory';
const history = createBrowserHistory();
const store = configureStore(history);
ReactDOM.render(
<Provider store={store}>
<Router
history={history}
children={routes}
{...clientOptions.props} />
</Provider>
, rootElement
);
...
And I see the store object, but I keep getting an error saying it's not there...
Adding requested additional code:
...
import rootReducer from '../reducers';
const middlewares = [
thunkMiddleware,
loggerMiddleware,
];
const finalCreateStore = compose(
applyMiddleware(...middlewares),
window.devToolsExtension ? window.devToolsExtension() : f => f
)(createStore);
export default function configureStore(history, initialState) {
const store = finalCreateStore(rootReducer, initialState);
syncReduxAndRouter(history, store, state => state.router);
return store;
}
...
...
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { clearNotification } from '../actions/notifications';
import { logout } from '../actions/auth';
import App from '../components/App';
function mapStateToProps(state) {
return {
locale: state.app.locale,
loggingIn: state.auth.loggingIn,
messages: state.app.messages,
notification: state.notification,
title: state.app.title,
user: state.auth.user,
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
clearNotification,
logout,
}, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
OK, here's the deal... it turns out that the demo app I am using code splits and if you add flux/redux into the mix in additional to all the 'joy' redux has already given, you actually need to 'split' your reducers as well per this repo.
The original error in my question above happened going to any non-root route because webpack code splitting makes those router calls async - basically getting things out of kilter with the reducer(s) in the store. The repo linked to in this answer shows how to keep the router and store in sync with the 'dynamic' reducers.
Am I the only one starting to feel like adding in redux is becoming more work than writing an entire large, complex app in the first place? Seeing those redux 10 line 'counter' app demos made it look so... easy? Anyway, hopefully this unveiling which by the way is not well documented in redux yet can help someone in the future!

Resources