mapStateToProps is not calling when same route is called again

88 Views Asked by At

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();

0

There are 0 best solutions below