'Please tell me how to save the changed value in redux store
I use usestate in the page to change the screen displayed when scrolling the html tag by adding a value of data. And when I leave the page, it is saved in the store to save the page scroll value and data. When you first save and return to that page, it returns to the desired scrolling position, but in that state, after scrolling and changing data, an error occurs to another page. I copied and used all the values stored in the store, but I don't know why it detects a mutation. Is it not possible to change the data to usestate in the page? I don't know which part is causing the problem. Help.
const [mainPage, setMainPage] = useState(store.mainPage.list.length ? store.mainPage : {list: [], scroll: 0});
const createScrollStopListener = (element, callback, timeout) => {
console.log('createScrollStopListener :: ');
if(document.querySelector('.body').scrollTop < 1) {
document.querySelector('.body').scrollTo({top: 1 , left: 0, behavior: "auto"});
}
let removed = false;
let handle = null;
const onScroll = () => {
if (handle) {
clearTimeout(handle);
}
handle = setTimeout(callback, timeout || 20 // default 200 ms
};
element.addEventListener('scroll', onScroll);
return () => {
if (removed) {
return;
}
removed = true;
if (handle) {
clearTimeout(handle);
}
element.removeEventListener('scroll', onScroll);
};
};
useEffect(() => {
let body = document.querySelector(".body")
body.addEventListener("scroll", function() {
mainThumbnailListDraw();
})
const destroyListener = createScrollStopListener(document.querySelector('.body'), () => {
console.log('createScrollStopListener ing... ::');
changeVideoImageTag();
});
return () => destroyListener(); // when App component is unmounted
}, [mainPage.list]);
const changeVideoImageTag = () => {
const mainPageCopy = {
...store.mainPage,
scroll: store.mainPage.scroll !== 0 ? store.mainPage.scroll : 0,
list: [
...mainPage.list,
],
};
console.log('changeVideoImageTag :: ', mainPageCopy);
let windowHeight = window.innerHeight
let thumbnailItem = document.querySelectorAll(".mainThumbnailItemImg");
thumbnailItem.forEach(function (value, index) {
let videoClientTop = value.getBoundingClientRect().top;
let videoClientHeight = value.getBoundingClientRect().height;
let valueIndex = mainPageCopy.list[index];
value.autoplay = true;
value.loop = true;
value.muted = true;
if(valueIndex) {
if (videoClientTop <= windowHeight && videoClientTop >= -videoClientHeight) {
// console.log('check :: ', index)
if (valueIndex.type == "VIDEO") {
// console.log('is_video? :: ', index)
let videoData = JSON.parse(valueIndex.vimeo_files);
valueIndex.videoTag = `<div className="mainThumbnailItemVideo">
<video class="mainThumbnailItemVideo" autoplay="" muted="" playsinline="" loop preload="metadata"data-wf-ignore="true" data-object-fit="cover" src=${videoData.fileList && videoData.fileList[0].url} type="video/mp4"/></div>`;
}
else {
valueIndex.videoTag = ""
}
}else {
valueIndex.videoTag = ""
}
}
})
setMainPage(mainPageCopy);
}
function mainThumbnailListDraw() {
console.log('그려진드앙 mainThumbnailListDraw :: ', mainPage);
let listJsx = mainPage.list.map(function (value, index) {
let videoData = '';
let videoPreview = '';
let imageData = '';
if (value.type == "VIDEO") {
videoData = JSON.parse(value.vimeo_files);
if(videoData.preview.url) {
let is_small = videoData.preview.url.split('/')
let num = is_small.length-1;
let result = is_small.splice(num,0,'scaled-w_600')
videoPreview = is_small.join('/');
}
} else if(value.type == "IMG") {
let is_small = value.image_url.split('/');
let num = is_small.indexOf('scaled-w_1000')
let result = is_small.splice(num,1,'scaled-w_600')
imageData = is_small.join('/');
} else {
return
}
return (
<li className="mainThumbnailItem" key={index} onClick={() => {
const mainPageCopy = {
...store.mainPage,
scroll: document.querySelector('.body').scrollTop,
list: [
...mainPage.list,
...store.mainPage.list.slice(mainPageList.length),
],
};
dispatch({ type: "mainPage/set", payload: mainPageCopy });
router.push(`/product/${value.product_seq}`);
}} ref={ref}>
<LazyLoadImage wrapperClassName="mainThumbnailItemImg" effect="opacity" src={videoData ? videoPreview : imageData} style={{position: "absolute", top: "0", left: "0", width: "100%", height: "100%", objectFit: "cover"}}></LazyLoadImage>
{value.videoTag ? <div dangerouslySetInnerHTML={{__html: `${value.videoTag}`}}/> : <></>}
<button className={`mainThumbnailItemWish wishButtonImg ${value.is_wish == true ? " is_wish" : ""}`} value={value.is_wish} type="button" onClick={(e) => {loginData.client_type ? (e.stopPropagation(), changeWishButton(e, value.product_seq, index)) : (e.stopPropagation(), script.userBlock(dispatch, router))}}/>
</li>
);
});
return listJsx;
}
Solution 1:[1]
Doing ...mainPage.list is not enough to clone the state, you need to clone the objects deep inside the list as well. You can either do it manually with the spread operator, or use one of those deep copy libraries (there are several on npm). The lazy dev's workaround is to use JSON.stringify together with JSON.parse, but that's slow.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | timotgl |

