1

I'm using the following code to be able to use the Panzoom JS lib in a custom block. This is a non-React library for panning and zooming elements using CSS transforms:

edit: (props) => {
        const blockProps = useBlockProps();
        const ref = useRef();
        const {
            attributes: { url, id, alt },
            setAttributes,
        } = props;

        const setImage = (media) => {
            setAttributes({ url: media.url, id: media.id, alt: media.alt });
        };

        useEffect( () => {
            if ( ref.current ) {
                var panzoom = Panzoom(ref.current, {
                    minScale: 1.1,
                    maxScale: 5,
                    startScale: 1.1,
                    animate: true,
                    duration: 1000,
                    origin: '50% 0'
                });
            }
        }, []);

        return (
            <>
                <InspectorControls>
                    <PanelBody
                        title={__('Settings', 'my-custom-block')}
                    >
                    </PanelBody>
                </InspectorControls>
                <BlockControls>
                    <MediaReplaceFlow
                        mediaId={id}
                        mediaUrl={url}
                        allowedTypes={['image']}
                        accept="image/*"
                        onSelect={setImage}
                        name={!url ? __('Add Image', 'my-custom-block') : __('Replace Image', 'my-custom-block')}
                    />
                </BlockControls>
                <div {...blockProps}>
                    <MediaUploadCheck>
                        {url &&
                            <div className="panzoom-parent">
                                <div className="panzoom-element" ref={ref}>
                                    <img
                                        className={`wp-image-${id}`}
                                        src={url}
                                        alt={alt}
                                    />
                                </div>
                            </div>
                        }
                        {!url &&
                            <MediaPlaceholder
                                accept="image/*"
                                allowedTypes={['image']}
                                onSelect={setImage}
                                value={id}
                                multiple={false}
                                handleUpload={true}
                                labels={
                                    { title: __('Panzoom Image', 'my-custom-block') }
                                }
                            />
                        }
                    </MediaUploadCheck>
                </div>
            </>
        );

    }

Everything is almost working as expected except when a new block is added and there's no image already selected. I select an image from the media library and the panning/zooming doesn't work until I save the page where the block is added and reload it. I imagine that the reason it doesn't work when a new block is added is because the reference returned by the useRef hook is not present in any DOM node the first time. Is there a way to add this reference automatically when a image selected without having to reload the page?

I hope I explained myself. Any help would be appreciated.

2
  • 1
    are you trying to apply panzoom to the a DOM that is managed by React? This looks like a generic react problem and a misunderstanding of how useEffect and dependencies work, not a WordPress problem, that effect only runs once and never updates again because the dependencies never change, aka [] will always be []
    – Tom J Nowell
    Commented May 10, 2023 at 14:41
  • Thanks, I added the url attribute as a dependency in useEffect and now the hook is called every time the image changes.
    – leemon
    Commented May 10, 2023 at 20:38

1 Answer 1

1

The problem is here:

        useEffect( () => {
            if ( ref.current ) {
                var panzoom = Panzoom(ref.current, {
                    minScale: 1.1,
                    maxScale: 5,
                    startScale: 1.1,
                    animate: true,
                    duration: 1000,
                    origin: '50% 0'
                });
            }
        }, []);

useEffect runs again when the dependencies parameter changes, but by providing none it will only run once.

If you want it to run again when the image URL changes, you need to declare that it depends on that variable so it re-runs when it changes

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.