Zeljko Marinkovic
Zeljko Marinkovic

Reputation: 55

Reducer updated with wrong value(array got updated with one item with few items inside instead spreading them)

i'm having hard time figure out this. Have component which is search filter and pushes all selected filters into url. Everything works like it should except in case of refresh, in that case reducer is updated for selected filter with array with single item in which i have all selected items, not spreaded into array.

f.e. i have url

myexampleapp.com/alltrips?tripType=short_walk,cycling,downhill_cycling,long_walks&season=spring,summer,alle,vinter&lengthTo=50

my reducer

// ------------------------------------
// Constants
// ------------------------------------
export const UPDATE_FILTERS = 'UPDATE_FILTERS';

// ------------------------------------
// Actions
// ------------------------------------
const updateFilter = (key, value) => ({
  type: UPDATE_FILTERS,
  payload: {
    key,
    value
  }
});

// ------------------------------------
// Action creators
// ------------------------------------
export const updateFilterState = (key, value) => {
  return dispatch => {
    dispatch(updateFilter(key, value));
  };
};

// ------------------------------------
// Reducer
// ------------------------------------
const initialState = {
  tripType: [],
  season: [],
  tripsTo: undefined,
  tripsFrom: undefined
};

export function filterReducer (state = initialState, action) {
  switch (action.type) {
  case UPDATE_FILTERS: {
    const key = action.payload.key;
    const value = action.payload.value;

    if (key === 'tripsFrom' || key === 'tripsTo') {
      return Object.assign({}, state, { [key]: value });
    } else {
      var newFilter = state[key].slice();
      var ttIdx = state[key].indexOf(value);

      if (ttIdx !== -1) {
        newFilter.splice(ttIdx, 1);
      } else {
        newFilter.push(value);
      }
    }
    console.log(newFilter);
    return Object.assign({}, state, { [key]: newFilter });
  }
  default:
    return state;
  }
}

console.log returns array with 1 element in which have array with 5 elements. but i want that 5 ekements to be in parrent array. and i'm parsing URL

  componentDidMount () {
    let {
      location: { search },
      updateFilterState
    } = this.props;

    search = search.slice(1);
    var queries = search.split('&');
    queries.forEach(q => {
      var tmp = q.split('=');
      if (tmp[0] && tmp[1]) {
        if (tmp[0].toLowerCase() === 'triptype') {
          updateFilterState(tmp[0], tmp[1].split(','));
          console.log(tmp[1].split(','));
        } else if (tmp[0].toLowerCase() === 'tripsto') {
          updateFilterState(tmp[0], tmp[1]);
        } else if (tmp[0].toLowerCase() === 'tripsfrom') {
          updateFilterState(tmp[0], tmp[1]);
        } else if (tmp[0].toLowerCase() === 'season') {
          updateFilterState(tmp[0], tmp[1].split(','));
        }
      }
    });
    this.updateQuery(this.props);
  }

So everything works except when i want to refresh.

Pretty new with all this, and been stuck for almost 3 days with this. Hope you understand what im trying to ask here as i'm pretty new and non-english speaker, so i don't know all the terms so i can better express myself. Can someone give me some pointers?

Upvotes: 0

Views: 125

Answers (1)

devserkan
devserkan

Reputation: 17608

If I'm not mistaken you are feeding the reducer with an array for season and tripType. So, when you try to update those values, you are not actually spreading that array. This is your value parameter. Hence, if you do this you will have a parent array with your desired result:

newFilter.push(...value);

... is ES6's spread syntax. So we are spreading our array and pushing it into our newFilter.

But again if I don't see it wrong you will have problems with this code since you are not checking the existence of your values right. You are looking indexOf something but if you really feeding your reducer with an array, for which one you are looking this index?

Here is a cleaner way of doing this if I'm not mistaken what you are trying to do here:

export function filterReducer (state = initialState, action) {
  switch (action.type) {
  case UPDATE_FILTERS: {
    const { key, value } = action.payload;
    if (key === 'tripsFrom' || key === 'tripsTo') {
      return { ...state, [key]: value };
    }  
    const newFilter = Array.isArray(value)
                  ? [ ...new Set( [ ...state[key], ...value ] ) ]
                  : [ ...new Set( [ ...state[key], value ] ) ];
    return { ...state, [key]: newFilter};
  }
  default:
    return state;
  }
}

Some differences with your code:

  • I am using spread syntax instead of Object.assign.
  • Instead of checking all the existence values (iterating the array and doing some logic) I'm using here Set object. It creates an object of unique values of what we give it. So I am cheating here and spreading our old state with spreading our value into an array, give this to our Set, and again at the top level spreading it again into an array. If you don't do the last spread you will get an object but here we want an array.

Upvotes: 1

Related Questions