简体   繁体   English

如何在 useEffect 的清理 function 中访问 state/redux 存储?

[英]How to access state/redux store in the useEffect's cleanup function?

I have form with a drag and drop component where I can upload images, after this I send these pictures with axios to my backend and save it on server side and then re-render it on my client side in a preview mode.我有一个带有拖放组件的表单,我可以在其中上传图像,之后我将这些带有 axios 的图片发送到我的后端并将其保存在服务器端,然后在我的客户端以预览模式重新渲染它。 My problem is, that if a user uploads some pictures and after that he switches to another page without submitting the form the added pictures are staying on my server side for no reason.我的问题是,如果用户上传了一些图片,然后他在没有提交表单的情况下切换到另一个页面,那么添加的图片会无缘无故地留在我的服务器端。 To solve this problem I tried to detect at cleanup function if the user leaves the page and this part is working fine.为了解决这个问题,我尝试在清理 function 时检测用户是否离开页面并且这部分工作正常。

And the problem:Inside the useEffect clear function I tried to access the state where I stored the image's path, but it always gave me the initial state.问题是:在 useEffect clear function 内部,我尝试访问存储图像路径的 state,但它总是给我初始的 Z9ED39E2EA931586B6A985A6942EF573E。 If I added the state as an input to useEffect then in every image adding/state modifying the clear function was fired and caused me error/unwanted behaviour.如果我添加了 state 作为 useEffect 的输入,那么在每个图像添加/状态中修改清除 function 被触发并导致我错误/不需要的行为。 So I decided to move my image links to a global redux store but when I try to acess this store I got the store's inital state too (which is an empty array) however there were elements in it.因此,我决定将我的图像链接移动到全局 redux 商店,但是当我尝试访问这家商店时,我也得到了商店的初始 state (这是一个空数组)但是里面有元素。 So my question is how to access the state/global state and clean my backend images in the clear function?所以我的问题是如何访问状态/全局 state 并在清晰的 function 中清理我的后端图像?

My code我的代码

function Product(props) {
 const globalStoreImgaes = useSelector(state => state.product.addedImages)
 const [Images,setImages] = useState([])
 
useEffect(() => {
        const initialObj = {
         ...key:values
        }
        dispatch(setProduct(initialObj)); // here I initialize my global state of my product when the page loads (the setProduct function transforms the initial object to another structure)
    }, []) // eslint-disable-line react-hooks/exhaustive-deps
    
    useEffect(() => {
            return function cleanup() {
                console.log('Leaving',globalStoreImgaes)
                console.log('Leaving',Images) // both of them are [] arrays however I have items in it

                ...axios call to delete from global store

             };
    }, []); // eslint-disable-line react-hooks/exhaustive-deps

const updateImages = (newImages) => {
        dispatch(refreshImage(newImages)) // this is where i update the global store
        setImages(newImages) // and my state too
    }
return (
 <Prompt when={isBlocking} message="There are unsaved datas. Are you sure you want to leave?"/> // if the user clicks yes the clear function activates 

 ...somecode)
}
export default Product

This is a classic closure issue, you cannot add dependencies to useEffect because you want the function to only run on component unmount but due to the fact that your useEffect only runs on initial render, the variables it used from closure are all stale when the component unmounts.这是一个经典的闭包问题,您不能将依赖项添加到 useEffect 因为您希望 function 仅在组件卸载时运行,但由于您的 useEffect 仅在初始渲染时运行,它从闭包中使用的变量在组件时都是陈旧的卸载。

To solve such scenarios, you will have to store state in ref like要解决这种情况,您必须将 state 存储在 ref 中,例如

function Product(props) {
 const globalStoreImgaes = useSelector(state => state.product.addedImages)
 const [Images,setImages] = useState([])
 const ImageRef = useRef({globalStoreImages, Images})
 useEffect(() => {
    ImageRef.current = {globalStoreImages, Images};
 }, [globalStoreImages, Images])
 
useEffect(() => {
        const initialObj = {
         ...key:values
        }
        dispatch(setProduct(initialObj)); // here I initialize my global state of my product when the page loads (the setProduct function transforms the initial object to another structure)
    }, []) // eslint-disable-line react-hooks/exhaustive-deps
    
    useEffect(() => {
            return function cleanup() {
                console.log('Leaving',ImagesRef.current.globalStoreImgaes)
                console.log('Leaving',ImagesRef.current.Images) 

                ...axios call to delete from global store

             };
    }, []); // eslint-disable-line react-hooks/exhaustive-deps

    const updateImages = (newImages) => {
        dispatch(refreshImage(newImages)) // this is where i update the global store
        setImages(newImages) // and my state too
    }

NOTE: If you do not like this approach, you can fallback to class components where you will not face this issues implementing componentWillUnmount.注意:如果您不喜欢这种方法,您可以回退到 class 组件,在这些组件中您不会遇到实施 componentWillUnmount 的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM