ninja
ninja

Reputation: 375

Move repetitive logic in reducers to utility function

I have been trying to write some codes in redux reducers where the logics of state updating are similar. My initial state looks like this:

const initialState = {
  isLoading: false,
  events: [
    {
      year: 2021,
      place: [
        {
          id: 1,
          name: "BD",
          address:[{id:1,text:"test"}]   
        },
        {
          id: 2,
          name: "BD Test"
          address:[{id:5,text:"test one"}]  
        }
      ]
    }
  ]
};

And, I have updated the state in reducer like this:

...state,
events: state.events.map((event) => ({
  ...event,
  place: event.place.map((place) => {
    const address = place.address.find((x) => x.id === action.addressId);
    if (address) {
      return {
        ...place,
        address: place.address.map((el) => {
          if (el.id === action.addressId) {
            return { ...el, isChanged:true };
          }
          return { ...el, isChanged:false };
        }),
      };
    }
    return place;
  }),
})),

I have been using this logic similarly in couple of places where i have just added some extra property like in this case "isChanged:true" and "isChanged:false". This portion of coded seems repetitive So, I have tried to write the utility function like this so far:

const updateAddress = (years, addressId, update) => years.map((year) => ({
  ...year,
  place: year.place.map((place) => place.address.find((el) => el.id === addressId)
    ? {
      ...place,
      address: place.address.map(
        (el) => el.id === addressId ? update(x) : x
      ),
    }
    : place),
}));

This utility function works fine but it only updates work when el.id === addressId becomes true and add only isChanged:true. But, I need to add also isChanged:false to other addresses just like the logic written in the reducer. Can anybody help with this how can I make that function works accordingly or is there any other options can I follow to move that logic to a utility function. Thanks in Advance.

Upvotes: 0

Views: 146

Answers (1)

lavor
lavor

Reputation: 1877

If I would follow your implementation of this "utility function", the solution is simple. In your original implementation, this:

place.address.map((el) => {
    if (el.id === action.addressId) {
        return { ...el, isChanged:true };
    }
    return { ...el, isChanged:false };
}

is this (in more clean and readable way):

place.address.map((el) => {
    let newElState;
    if (el.id === action.addressId) {
        newElState = { ...el, isChanged:true };
    } else {
        newElState = { ...el, isChanged:false };
    }
    return newElState;
}

Hence, you are doing 2 things:

  1. You are updating somehow item with some id (passed as an argument of your utilit function).
  2. You are updating somehow (but maybe differently) all other items.

So, you need to pass another updater as an argument of your utility function:

const updateAddress = (years, addressId, updateId, updateOthers) => years.map((year) => ({
  ...year,
  place: year.place.map((place) => place.address.find((el) => el.id === addressId)
    ? {
      ...place,
      address: place.address.map(
        // this arrow function works in the same way as the code snippet above:
        // 1. if an address in the place.address arrray has the same id
        //    as id passed in addressId, the callback updateId will be called
        // 2. if an address in the place.address arrray does not have the same id
        //    as id passed in addressId, the callback updateOthers will be called
        //
        // what really updateId, or updateOthers do depends on their implementation,
        // what the caller of updateAddress put as the third and the fourth argument
        (el) => el.id === addressId ? updateId(el) : updateOthers(el)
      ),
    }
    : place),
}));

Upvotes: 1

Related Questions