Ожидаемое поведение - я загружаю фотообъект и отображаю его в своем компоненте. С помощью приведенного ниже кода я достигаю результата, но с некоторыми неожиданными эффектами, которые в итоге делают этот компонент бесполезным - см. Дальнейшее описание в двух частях. Я действительно хочу погрузиться в причину всего этого и понять, как я могу предотвратить такое поведение в моем приложении. Я попробовал некоторые предложения от других людей, похожих проблем, но ничего не помогло. Я не буду перечислять здесь то, что я пробовал, потому что, очевидно, каждый раз, когда я пытался - я делал что-то не так, потому что это не помогало мне. Буду благодарен за любые идеи и предложения - я что-то упускаю и не могу понять, что это.
Часть 1 проблемы. При загрузке этого компонента в первый раз и / или обновлении - я получаю несколько повторных обращений. Из Redux DevTools я могу заметить, что действия запускаются два раза, запись в консоль любого полученного из фото значения показывает, что это значение появляется в консоли 6 раз (первые 3 раза - с исходным состоянием из хранилища redux, после -с ожидаемым извлеченным из значения объекта фото).
Часть 2 проблемы. Когда я открываю следующую фотографию (тот же компонент, просто пропуская другой match.params.id) - компонент начинает перерисовываться, по-видимому, в случайное время. Для завершения этого цикла рендеринга может потребоваться несколько секунд, поэтому он рендерится иногда на десятки, иногда более 100 раз, но всегда в конце выдает необходимую информацию. Анализируя логи, я увидел, что значения выбранной фотографии теперь просто переключаются в цикле со значениями фотографии, выбранной ранее. Цикл останавливается с правильными значениями. А откуда из предыдущих значений приходят значения - я не могу понять, потому что перед извлечением нового фотообъекта я очищаю все данные предыдущего в избыточном состоянии.
Компонент:
//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;
useEffect(() => {
getPhotoById(photoID);
}, [getPhotoById, photoID]);
useEffect(() => {
if (loading === false) {
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]);
useEffect(() => {
if (!loading) {
initOpenseadragon();
}
}, [loading]);
console.log(photoFileName, 'photoFileName');
const initOpenseadragon = () => {
OpenSeadragon({
id: 'viewer',
tileSources: `/uploads/tiles/${photoFileName}.dzi`,
prefixUrl: '/images/osd/',
showZoomControl: true,
showHomeControl: true,
showFullPageControl: true,
showRotationControl: true
});
};
return !photo && !loading ? (
<NotFound />
) : (
<Fragment>
SOME JSX
</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);
АКЦИЯ:
export const getPhotoById = photo_id => async dispatch => {
try {
dispatch({ type: CLEAR_PHOTO });
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 }
});
}
};
РЕДУКТОР
const initialState = {
photo: null,
photos: [],
loading: true,
error: {}
};
const photo = (state = initialState, action) => {
const { type, payload } = action;
switch (type) {
case GET_PHOTO:
return {
...state,
photo: payload,
loading: false
};
case LOAD_PHOTO:
return {
...state,
loading: true
};
case CLEAR_PHOTO:
return {
...state,
photo: null,
loading: false
};
case PHOTOS_ERROR:
return {
...state,
error: payload,
loading: false
};
default:
return state;
}
};
export default photo;