skip to Main Content

I have a simple block, code below, that contains a component that fetches image data, including a URL and a pid, using a custom REST call. The registerBlockType edit method contains the component, displaying the image, and a number control. With fetch calls in the component’s componentDidUpdate() & componentDidMount() methods, when the value of the number control changes, new data is fetched and the image display updates accordingly. This works fine; the image updates and when I save using the update button in the page editor I can refresh the editor and the block loads with the updated image. However, when I try and preview the page, neither DidMount nor DidUpdate are called in the save method and the preview page shows my image failed to load message. Any idea how I deal with this?

index.js:


import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps } from '@wordpress/block-editor';
import { __experimentalNumberControl as NumberControl } from '@wordpress/components';

import {PnImage} from './PnImage.js'

registerBlockType( 'create-block/pn-test', {
    
    attributes: {
        pid: {
            type: "number",
            default: 8
        },
    },

    edit: ( {attributes, setAttributes} ) => {
    
        console.log( "Edit", attributes )
        return (
            <p { ...useBlockProps() }>
                 {"Editoor " + attributes.pid}
                <PnImage pid={attributes.pid}/>
                <NumberControl
                    label="PID"
                    isShiftStepEnabled={ true }
                    onChange={ value => { setAttributes( {pid: value})} }
                    shiftStep={ 10 }
                    value={ attributes.pid }
                />

            </p>
        )
    },

    save: ({ attributes }) => {

        return (
            <p { ...useBlockProps.save() }>
                { "Saved " + attributes.pid}
                <PnImage pid={attributes.pid}/>c
            </p>
        )
    }
})

PnImage.js, component code

import React, { Component } from 'react';

export class PnImage extends Component {
    
    static defaultProps = {
        size:   "large",
        pid:    null,
    }

    constructor(props) {
        super(props);
        this.state = {
            image: null,
            pid: null
        };
    }

    componentDidMount() {           // initially fetch data
        console.log( "DidMount, pid: ", this.props.pid)
        this.Fetch()
    }
    componentDidUpdate() {          // fetch data when props.pid changes
        console.log( "DidUpdate, pid: ", this.props.pid)
        this.Fetch()
    }

    render() {

        const {image} = this.state;

        return (
            <p>
                Image Component<br/>
                { image ? <img src={image.URL} /> : "no  image found loaded for pid " + this.props.pid }
            </p>
        )
    }

    Fetch() { // fetch wrapper

        if (this.props.pid != this.state.pid && this.props.pid ) {
            console.log( "fetching: pid=", this.props.pid )
            pnRest.Fetch('image/get', { pid: this.props.pid, size: this.props.size })
                .then(data => {
                    if ( data ) {       // image not found returns undefined
                        this.setState({ image: data, pid: data.id })
                    } else {
                        console.log( "Couldn't find image for pid " + this.props.pid )
                    }
                });
        }

    }

}

2

Answers


  1. Chosen as BEST ANSWER

    After a bit of messing about, here's the solution I came up with. Working with Phil's suggestion, rather than pass setAttributes to the pnImage component, I've shifted the Fetch function into my edit function, using it in the number control callback and, so the component can be populated when it's first mounted, I pass Fetch to the component and call it in componentDidMount. Seems to work well enough.

    Thanks for the help, Phil.

    
    import { registerBlockType } from '@wordpress/blocks';
    import { useBlockProps } from '@wordpress/block-editor';
    import { __experimentalNumberControl as NumberControl } from '@wordpress/components';
    
    import {PnImage} from './PnImage.js'
    
    registerBlockType( 'create-block/pn-test', {
        
        attributes: {
            pid: {
                type: "number",
                default: 8
            },
            image:  {
                type: "object",
                default: null
            },
        },
    
        edit: ( {attributes, setAttributes} ) => {
        
            console.log( "Edit", attributes )
    
            function Fetch( pid ) { // fetch wrapper
    
                pnRest.Fetch('image/get', { pid: pid, size: 'large' })
                    .then(data => {
                        if ( data ) {       // image not found returns undefined
                            setAttributes({ image: data, pid: pid })
                        } else {
                            console.log( "Couldn't find image for pid <" + pid + ">" )
                            setAttributes({ image: null,  pid: -1 })
                        }
                    });
            }
    
            return (
                <p { ...useBlockProps() }>
    
                    <PnImage 
                        pid={attributes.pid} 
                        image={attributes.image}
                        Fetch={Fetch}
                    />
    
                    <NumberControl
                        label="PID"
                        isShiftStepEnabled={ true }
                        onChange={ value => { if ( value == "" ) {return }; Fetch( value ) } }
                        shiftStep={ 10 }
                        value={ attributes.pid }
                    />
    
                </p>
            )
        },
    
        save: ({ attributes, setAttributes }) => {
    
            return (
                <p { ...useBlockProps.save() }>
                    <PnImage 
                        pid={attributes.pid} 
                        image={attributes.image}
                    />
                </p>
            )
        }
    })
    
    import React, { Component } from 'react';
    
    export class PnImage extends Component {
        
        static defaultProps = {
            size:   "large",
            pid:    null,
            image: null,
            Fetch: null
        }
    
        constructor(props) {
            super(props);
    
            this.state = {
                image: null,
                pid: null
            };
        }
    
        componentDidMount() {           // initially fetch data
            console.log( "DidMount, pid: ", this.props.pid)
            this.props.Fetch( this.props.pid )
        }
        render() {
    
            const image = this.props.image;
    
            if ( this.props.pid == -1 ) {
                return (
                    <p>
                        Image couldn't be fetched
                    </p>
                )
            }
            return (
                <p>
                    Image Component<br/>
                    { image ? <img src={image.URL} /> : "no  image found loaded for pid " + this.props.pid }
                </p>
            )
        }
    
    }
    
    

  2. I don’t think you can run async functions inside the save() function. So it will never save the returned data. Instead what you should do is fetch the data, then save the fetched data to attributes of the block (e.g. pid and src. Then use those saved attributes in the save() function. You can pass the setAttributes() function into your PnImage class as a prop and access it directly:

    <PnImage 
      pid={ attributes.pid }
      setAttributes={ setAttributes }
    />
    

    Then, within Fetch() {}, something like this:

    pnRest.Fetch('image/get', { 
        pid: this.props.pid, 
        size: this.props.size 
    }).then(data => {
        if (data) {
            this.props.setAttributes({ 
                src: data.src, 
                pid: data.id 
            });
        }
    );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search