Felipe V
Felipe V

Reputation: 621

Redux Selector not called

I have the following situation:

A selector for a list of countries in my app state

export const getCountries = state => state.countries;

And a selector created using reselect to filter for a country with a specific id

export const getCountryById = countryId => 
    createSelector(
        [getCountries],
        (countries) => {
            let countriesList = countries.filter(c => c.id === countryId);
            if ( countriesList ) {
                return countriesList[0];
            }
            return null;
        }
    )

Then a have a country details page component ( acessed through http://localhost:3000/country/4 )

import React from 'react';
import { getCountryById } from '../redux/selectors';
import { connect } from 'react-redux';

const CountryPage = ({country}) => {
    return <h1>{country.name}</h1>
}

const mapStateToProps = (state, ownProps) => {
    console.log(ownProps.match.params.countryId);
    const obj = {
        country: getCountryById(ownProps.match.params.countryId)
    }
    return obj;
};

export default connect(mapStateToProps, null)(CountryPage);

The mapStateToProps is correctly receiving the countryId, but the selector is not being called. What am I missing here ?

Or is it the wrong approach to using the selectors ? I am aware that I can use the full country list from state in the CountryPage and filter it there, but what is the best practice here ?

Upvotes: 0

Views: 1055

Answers (1)

markerikson
markerikson

Reputation: 67459

That's because your getCountryById isn't actually a selector. It's a function that returns a selector.

Given that you are trying to use a unique ID per component, and doing filtering, you probably need to use the "factory function" form of mapState to create a unique selector instance per component instance to get proper memoization behavior.

However, having said that, your selector can also be simplified. You don't need a filter() here, you need a find(), and that means it's also not something that really needs to be memoized. This can be simplified down to:

const getCountryById = createSelector(
    [getCountries, (state, id) => id],
    (countries, id) => countries.find(c => c.id === id) || null
)

and then used as:

const mapStateToProps = (state, ownProps) => {
    return  {
        country: getCountryById(state, ownProps.match.params.countryId)
    }
};

Upvotes: 1

Related Questions