Firstly, I'm using
"react": "^16.13.0",
functional components only, not classes, along with
"react-redux": "^7.2.0", "react-router": "^5.2.0", "redux": "^4.0.5", "redux-saga": "^1.1.3", "webpack": "^4.42.0",
I've 2 components in react component - landingPage.js
which gets the favorite values from localStorage and stores it to redux-store on initial render.
When I navigate to favorites component, it calls the mapDispatchToProps
, fetches the favsList
values from store -> selector and renders the list.
When I try to hit the favorites (same component) button while still being in favorites, mapStateToProps
is not getting called and so not rendering the favsList
. While I still see the state intact in redux store, not changed.
> Question 1:
If the state doesn't changes (here if favsList is not updated) mapStateToProps won't get called? If yes, why is it working when I'm coming back from landingPage.js
to favorites.js
and not from favorites.js
to favorites.js
?
> Question 2: What's the alternate way to trigger mapStateToProps
on initial component render?
EDIT adding code snippets:
Here's the landingPage:
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { fetchItemDetailsRequest, saveItemToFavSuccess } from '../Services/actions';
import { lastCatRouteSelector, favListSelector } from '../Services/selectors';
import Home from '../Components/Common/home';
function Home({
itemData,
dispatchItemData,
handleSwitch,
selectedLanguage,
dispatchSetInitialFavList,
}) {
useEffect(() => {
dispatchSetInitialFavList();
}, []);
return (
<div className={coreStyles.mainContent}>
<Home />
</div>
);
}
const mapStateToProps = (state) => ({
itemData: lastCatRouteSelector(state),
});
const mapDispatchToProps = (dispatch) => ({
dispatchItemData: () => {
dispatch(fetchItemListRequest());
},
dispatchSetInitialFavList: () => {
dispatch(saveItemToFavSuccess());
},
});
export default connect(mapStateToProps, mapDispatchToProps)(DLJHome);
In the above you I want you to see at the
dispatchSetInitialFavList: () => {
dispatch(saveItemToFavSuccess());
},
which saves the favList to store. The corresponding actions.js
export const saveItemToFavSuccess = (itemId, fetchedItems) => {
let favList = !localStorage.getItem('favList')
? []
: JSON.parse(localStorage.getItem('favList')).length > 1
? JSON.parse(localStorage.getItem('favList'))
: [JSON.parse(localStorage.getItem('favList'))[0]];
itemId ? favList.push(itemId.toString()) : null;
localStorage.setItem('favList', JSON.stringify(favList));
return {
type: SAVE_ITEM_TO_FAV_SUCCESS,
payload: fetchedItems ? [favList, fetchedItems] : [favList],
};
};
- sagas.js:
function* saveItemToFav() {
yield takeEvery(SAVE_ITEM_TO_FAV_REQUEST, saveItemToFavRequest);
}
function* saveItemToFavRequest(action) {
try {
const itemId = action.payload;
const existingFavs = yield select(favListSelector);
yield put(saveItemToFavSuccess([itemId]));
} catch (saveFavError) {
console.warn('Error occured while saving to fav', saveFavError);
}
}
export default function* rootSaga() {
yield all([fetchItemDetails(), saveCatRoute(), saveItemToFav(), saveItemRoute()]);
}
- reducers.js
function saveItemToFavReduer(state = null, action) {
switch (action.type) {
case SAVE_ITEM_TO_FAV_SUCCESS:
return { favList: deducePayload(action) };
default:
return state;
}
}
const itemCategoryReducer = combineReducers({
favList: saveItemToFavReduer,
});
const deducePayload = (action) => {
return action.payload;
};
export default itemCategoryReducer;
And finally, here's the
- favorites.js
where the
console.log('inFavs', favList);
returns empty/null array
import { connect } from 'react-redux';
import { itemDetailsSelector, favListSelector } from '../../Services/selectors';
import { saveItemToFavReduer } from '../../Services/reducers';
function Favorites({ favList, itemDetails, dispatchFetchItemData }) {
console.log('inFavs', favList);
);
}
const mapStateToProps = (state) => ({
favList: state.favList,
itemDetails: state.itemDetails ? state.itemDetails : [],
});
const mapDispatchToProps = (dispatch) => ({
dispatchFetchItemData: (itemId) => {
dispatch(fetchItemDetailsRequest(itemId));
},
});
export default connect(mapStateToProps, mapDispatchToProps)(Favorites);
- App.js
import React, { useState } from 'react';
import { IntlProvider, FormattedMessage } from 'react-intl';
import messages from './Core/i18n';
import { HashRouter, Route, Switch, withRouter } from 'react-router-dom';
import Home from './Components';
import Favorites from './Components/Common/favorites';
function App() {
const [locale, setLocale] = useState(
localStorage.getItem('localValue') ? localStorage.getItem('localValue') : 'en',
);
const handleSwitch = (language) => {
setLocale(language);
localStorage.setItem('localValue', language);
};
return (
<IntlProvider locale={locale} messages={messages[locale]}>
<Switch>
<Route
exact={true}
path="/"
component={() => <Home handleSwitch={handleSwitch} selectedLanguage={locale} />}
/>
<Route
exact={true}
path="/home"
component={() => <Home handleSwitch={handleSwitch} selectedLanguage={locale} />}
/>
<Route path="/categories/" component={ItemCategory} />
<Route path="/favorites/" component={Favorites} />
</Switch>
</IntlProvider>
);
}
export default withRouter(App);
- index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import 'regenerator-runtime/runtime';
import 'core-js/stable';
import { HashRouter, Route, Switch, withRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './Services/store';
const title = 'Title';
ReactDOM.render(
<Provider store={store}>
<HashRouter>
<App title={title} />
</HashRouter>
</Provider>,
document.getElementById('app'),
);
module.hot.accept();