I'm attempting to set up a redux store that is accessible from multiple components. I'm new to this, but I understand that normally one would wrap the root app component with the provider to make the same store context available everywhere.
However, I'm working within a legacy app, where we're tacking on React components here and there and there's no site-wide common root app component, only separate components trees that know nothing about each other. I thought a redux store would be a good solution to this, but now realize that there's some context handling going on behind the scenes and I'm not sure how to wire up each provider with the same context. I found some basic info on providing a context, but I'm not sure if this solves my problem or not and it's getting into the weeds, especially using Typescript.
Specifically, I have a mini-cart in the header and several pages that want to interact with that component. I have things working on both sides, but they are affecting different stores.
MiniCart.tsx:
import store from '../../common/stores/store';
...
<Provider store={store}>
<MiniCart />
</Provider>
PageThatNeedsToAddToMiniCart.tsx:
import store from '../../common/stores/store';
...
<Provider store={store}>
<PageThatNeedsToAddToMiniCart />
</Provider>
--- EDIT 1 ---
hooks.ts:
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
type DispatchFunc = () => AppDispatch
const useAppDispatch: DispatchFunc = useDispatch
const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export { useAppDispatch, useAppSelector }
miniCartSlice.tsx:
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import type { RootState } from './store';
interface MiniCart {
SubTotal: number;
}
interface MiniCartState {
SubTotal: number;
}
const initialState: UserCart = {
SubTotal: 0,
}
const miniCartSlice = createSlice({
name: 'miniCart',
initialState: initialState,
reducers: {
productAdded: (state, action: PayloadAction<UserCart>) => {
return state = action.payload;
}
}
});
const selectSubTotal = (state: RootState) => state.miniCart.SubTotal;
export const { productAdded } = miniCartSlice.actions;
export { selectSubTotal };
export default miniCartSlice.reducer;
store.tsx:
import { configureStore } from '@reduxjs/toolkit';
import miniCartReducer from './miniCartSlice';
const store = configureStore({
reducer: {
miniCart: miniCartReducer
}
})
type RootState = ReturnType<typeof store.getState>;
type AppDispatch = typeof store.dispatch;
export type { RootState, AppDispatch }
export default store;
PageThatNeedsToAddToMiniCart.tsx:
const dispatch = useAppDispatch();
...
dispatch(
productAdded(result.UpdatedCart)
);
MiniCart.tsx:
//This value is not updated when the other component dispatches "productAdded". I expected it to trigger a rerender.
const subTotal = useAppSelector(selectSubTotal);
...
return (
<div>
<p>{`Subtotal: ${subTotal} `}</p>
</div>
);
Maybe I'm misunderstanding what I'm seeing debugging, but the two components appear to access separate stores.
--- EDIT 2 ---
It turns out that, while I'm configuring the store once, bundling the apps separately results in separate stores. I ended up going with Jacob's answer for simplicity, but may end up going with his more robust suggestion of redux-micro-frontend down the road.
Providercomponent provides astoreobject to the sub-ReactTree it is wrapping? What exactly is the issue with what you are trying to do here? What isn't working? Is the issue that "I have things working on both sides, but they are affecting different stores." - you should have one single app store if you are wanting any consumers to read/update the same state.connectHigher Order Component only connects a component to the nearestProvidercomponent providing the store. I guess what I'm asking is if the issue is because you are using two different app stores. What I think both Jacom and I are suggesting is to pass the same store to both providers. Does that make sense?storereference is the same for any consumers that import it. It's only configured once then exported.