How to avoid duplicate image urls on click in Redux

Viewed 95

I'm working on a React-Redux app.

I fetch a random image URL from Unsplash API and have two options: approve it or reject. onApprove the image lands into a gallery.

I noticed that if I click onApprove button quickly multiple times, then I put duplicate images into my gallery. I know that in React you can do something like this to be able to handle actions

setState(prevState) => {return prevState + 1} 

But here comes Redux. I use createSlice() to take care of the reducers. Here is the code snippet with the functionality

const imagesSlice = createSlice({
  name: 'images',
  // The intial state value we pass for the reducers. A state the first time it gets called.
  initialState,
  reducers: {
    imageApproved(state, action) {
      state.approvedImageList.push(action.payload);
    },
  },
});

And later on I dispatch an action in my Footer where buttons are:

function Footer({ randomImageUrl, generateNewRandomImage }) {
  const dispatch = useDispatch();

  function onApprove() {
    dispatch(imageApproved(randomImageUrl));
    generateNewRandomImage();
  }


  const showButton = useSelector((state) => state.buttons.showButton);

  return (
    <FooterWrapper>
      {showButton ? (
        <FooterCopy>
          Click on the + in order to get image recommendations
        </FooterCopy>
      ) : (
        <ButtonWrapper>
          <Button bgColorOnHover='true' onClick={onApprove}>
            APPROVE
          </Button>
        </ButtonWrapper>
      )}
    </FooterWrapper>
  );
}

So how can I avoid duplicating images onClick? Thanks!

here is an example with duplicates

PLUS: I've got a question:

when I fetch data from the API, I only fetch the imageUrl. That means that I am not checking Ids in my code, but only imageUrls. Idk if it could be the reason for the duplicates as well, but do I have to fetch the Ids and check them with .includes() as well?

2 Answers

You can check new Url in the approvedImageList or not before push:

imageApproved(state, action) {
  const url = action.payload;
  if(!state.approvedImageList.includes(url)){
    state.approvedImageList.push(url);
  }
},

nothing redux-specific here:

    imageApproved(state, action) {
      if (!state.approvedImageList.includes(action.payload)) {
        state.approvedImageList.push(action.payload);
      }
    },
Related