React-redux and hooks: a function in the component getting arguments twice - one from prev redux state and one from current

I've got a rather simple component that is fetching an photo object from redux state and renders it. One of the fetched value (photoFileName) is getting passed to the OpenSeaDragon as a part of argument. OpenSeaDragon renders a photo based on it (in the div with the id which is also passed as an argument).

The problem - somehow OpenSeaDragon gets it's arguments twice - one photoFileName from previous redux state, and another photoFileName from current redux state. And it renders two photos as the result. In the same time all the other values which are getting fetched with the photoFileName (photoID, title, description, etc) are getting rendered only with the current redux state values (as expected).

I console.log the photoFileName and it shows the following for one component render:

*(empty string)* photoFileName
Photo.js:206 *(previous value from redux state)* photoFileName
Photo.js:206 *(previous value from redux state)* photoFileName
Photo.js:206 *(current value from redux state)* photoFileName

The question is - why it's happening and how I can avoid it? I've tried even conditional rendering just simply to hide the unneeded rendered photo, but everytime all my checks fail.

Obviously I am doing something wrong here and most probably it has nothing to do with OpenSeaDragon. I've spended so many hours trying to figure it out, bur since it's my first React app I probably just missing something. Need some fresh eyes to see my code, some advices and pushing into the right direction. Thanks!

APP.JS

const App = () => {
  return (
    <div>
      <Provider store={store}>{router}</Provider>
    </div>
  );
};

REDUX STORE

const initialState = {};
const middleware = thunk;

const store = createStore(
  rootReducer,
  initialState,
  composeWithDevTools(applyMiddleware(middleware))
);

API

router.get('/:photo_id', async (req, res) => {
  try {
    const photo = await Photo.findOne({
      photoID: req.params.photo_id
    });
    if (!photo) return res.status(400).json({ msg: 'Photo not found' });
    res.json(photo);
  } catch (err) {
    console.error(err.message);
    if (err.kind === 'ObjectId') {
      return res.status(400).json({ msg: 'Photo not found' });
    }
    res.status(500).send('Server error');
  }
});

ACTION

export const getPhotoById = photo_id => async dispatch => {
  try {
    dispatch({ type: LOAD_PHOTO });
    const res = await axios.get(`/api/photo/${photo_id}`);

    dispatch({
      type: GET_PHOTO,
      payload: res.data
    });
  } catch (err) {
    dispatch({
      type: PHOTOS_ERROR,
      payload: { msg: err.response.statusText, status: err.response.status }
    });
  }
};

REDUCER

const initialState = {
  photo: null,
  photos: [],
  loading: true,
  error: {}
};

const photo = (state = initialState, action) => {
  const { type, payload } = action;
  switch (type) {
   case LOAD_PHOTO:
      return {
       ...state,
       loading: true
      };
    case GET_PHOTO:
      return {
        ...state,
        photo: payload,
        loading: false
      };


    default:
      return state;
  }
};

THE COMPONENT (PHOTO.JS)

//IMPORTS

const Photo = ({ getPhotoById, photo, loading, match }) => {
  const [photoData, setPhotoData] = useState({
    photoID: match.params.id,
    imgUrl: '',
    photoFileName: '',
    title: '',
    description: '',
    albumID: '',
    albumName: '',
    categoryID: '',
    categoryName: '',
    categoryID2: '',
    categoryName2: '',
    categoryID3: '',
    categoryName3: '',
    locationID: '',
    locationName: '',
    contributorID: '',
    contributorName: '',
    contributorWeb: '',
    source: '',
    sourceWeb: '',
    author: '',
    periodID: '',
    periodName: '',
    license: ''
  });

  const {
    photoID,
    imgUrl,
    photoFileName,
    title,
    description,
    albumID,
    albumName,
    categoryID,
    categoryName,
    categoryID2,
    categoryName2,
    categoryID3,
    categoryName3,
    locationID,
    locationName,
    contributorID,
    contributorName,
    source,
    sourceWeb,
    author,
    periodID,
    periodName,
    license
  } = photoData;

  const getPhotoByIdRef = useRef();
  getPhotoByIdRef.current = getPhotoById;

  useEffect(() => {
    getPhotoByIdRef.current(photoID);
  }, [getPhotoByIdRef]);
//Can't pass photoID as a second dependency because, while rendering, photoID also switches from previous redux state value to current which causes an infinite loop

  useEffect(() => {
    if (loading === false && photo !== null) {
      const {
        photoID,
        imgUrl,
        photoFileName,
        title,
        description,
        albumID,
        albumName,
        categoryID,
        categoryName,
        categoryID2,
        categoryName2,
        categoryID3,
        categoryName3,
        locationID,
        locationName,
        contributorID,
        contributorName,
        source,
        sourceWeb,
        author,
        periodID,
        periodName,
        license
      } = photo;

      setPhotoData({
        photoID,
        imgUrl,
        photoFileName,
        title,
        description,
        albumID,
        albumName,
        categoryID,
        categoryName,
        categoryID2,
        categoryName2,
        categoryID3,
        categoryName3,
        locationID,
        locationName,
        contributorID,
        contributorName,
        source,
        sourceWeb,
        author,
        periodID,
        periodName,
        license
      });
    }
  }, [loading, photo]);


  useEffect(() => {
    if (loading === false && photoFileName !== '') {
      initOpenseadragon();
    }
  }, [loading, photoFileName]);

  const initOpenseadragon = () => {
    OpenSeadragon({
      id: 'viewer',
      tileSources: `/uploads/tiles/${photoFileName}.dzi`,
      prefixUrl: '/images/osd/',
      showZoomControl: true,
      showHomeControl: true,
      showFullPageControl: true,
      showRotationControl: true
    });
  };

   console.log(photoFileName, 'photoFileName');


  return !photo && !loading ? (
    <NotFound />
  ) : (
    <Fragment>
         //Successefully rendering the current value of title, description


//OpenSeadragon renders two photos instead of one (one for previous redux state value, other - for current)
         <div className={styles.PhotoPage}>
            {loading ? (
              <Spinner />
            ) : (
              <Fragment>
                <div id='viewer' className={styles.Viewer} />
              </Fragment>
            )}

            <div className={styles.PhotoDescription}>
             //Successefully rendering the current value of other data from redux state
             </div>
    </Fragment>
  );
};

Photo.propTypes = {
  getPhotoById: PropTypes.func.isRequired,
  photo: PropTypes.object.isRequired,
  loading: PropTypes.bool.isRequired
};

const mapStateToProps = state => {
  return {
    photo: state.photo.photo,
    loading: state.photo.loading
  };
};

export default connect(
  mapStateToProps,
  { getPhotoById }
)(Photo);