WP Gutenberg блок Передача props между бекэндом и фронтэндом

Прохожу курс по созданию Gutenberg блоков для WordPress. Есть вот такие 2 файла. src/index.js

import "./index.scss"
import {TextControl, Flex, FlexBlock, FlexItem, Button, Icon, PanelBody, PanelRow, ColorPicker} from '@wordpress/components'
import {InspectorControls, BlockControls, AlignmentToolbar, useBlockProps } from '@wordpress/block-editor'
import { __ } from '@wordpress/i18n'
import {sanitizeText} from '@wordpress/server-side-render';



wp.blocks.registerBlockType(
    'gcb/custom-questionnaire', {
        title: __('Questionnaire block', 'gcb'),
        description: __('Gives your audience to do a survey of important issues', 'gcb'),
        icon: 'editor-help',
        category: 'text',
        attributes: {
            question: {type: "string"},
            answers: {type: "array", default: [""]},
            correctAnswer: {type:"number", default: undefined},
            theAlignment: {type:"string", default:"left"}
        },

        example:{
          attributes:{
              question: __('What are the three basic questions of life?', 'gcb'),
              correctAnswer: 3,
              answers: [__('Who am I?', 'gcb'), __('Why am I here?', 'gcb'), __('What happens after I die?', 'gcb')],
              theAlignment: "center",
          }
        },

        edit: EditComponent,
        save: function (props) {
            return null
        }
    })

function EditComponent(props) {
    const blockProps = useBlockProps({
        className:"gcb_adm__box",

        }
    )

    function updateQuestion(value) {
        const sanitizedValue = sanitizeText(value);
        props.setAttributes({ question: sanitizedValue });
    }

    function deleteAnswer(indexToDelete){
        const newAnswers = props.attributes.answers.filter(
            function (x, index){
                return index !== indexToDelete
            }
        );
        props.setAttributes({ answers:newAnswers})

        if( indexToDelete === props.attributes.correctAnswer){
            props.setAttributes( {correctAnswer: undefined})
        }
    }



    function markAsCorrect(index){
        props.setAttributes({correctAnswer: index})
    }



    return (
        <div  {...blockProps} >

            <BlockControls>
                <AlignmentToolbar value={props.attributes.theAlignment} onChange={x => props.setAttributes({theAlignment: x})} />
            </BlockControls>

            <InspectorControls>
                <PanelBody title={__("Supplementing questionnaire data", 'gcb')} initialOpen={true}>
                    <PanelRow>
                        test
                    </PanelRow>
                </PanelBody>
            </InspectorControls>


            <TextControl label={__("Write name of Questionnaire", 'gcb')} value={ props.attributes.question} onChange={updateQuestion}  style={{fontSize: "20px"}} />
            <p style={{fontSize:"13px", margin: "20px 0 8px 0"}}>{__('Answers:', 'gcb')}</p>

            {/* SET data for all answers */}
            {props.attributes.answers.map(function (answer, index){
                return (
                    <Flex>
                        <FlexBlock>
                            <TextControl  value={answer} onChange={newValue => {
                                const newAnswers = props.attributes.answers.concat([]);
                                newAnswers[index] = newValue
                                props.setAttributes({ answers: newAnswers})
                            } } />
                        </FlexBlock>
                        <FlexItem>
                            <Button onClick={ () => markAsCorrect(index) }>
                                <Icon className={"gcb_icon-star"} icon={ props.attributes.correctAnswer === index ? 'star-filled' : 'star-empty' } />
                            </Button>
                        </FlexItem>
                        <FlexItem>
                            <Button className={"gcb_delete"} onClick={ () => deleteAnswer(index) }>{__('Delete', 'gcb')}</Button>
                        </FlexItem>
                    </Flex>
                )
            } )}
            <Button isPrimary className={"gcb_addNew__button"} onClick={ () => {
                props.setAttributes({answers: props.attributes.answers.concat([""])})
            }} >{__('Add another answer', 'gcb')}</Button>
        </div>
    )
}

и фронтовий файл представления элемента /src/frontend.js

import React, {useState, useEffect} from "react";
import ReactDOM from "react-dom";
import "./frontend.scss"

const divsToUpdate = document.querySelectorAll(".gcb_item");

divsToUpdate.forEach(function (div){
    const data = JSON.parse(div.querySelector("pre").innerHTML)
    ReactDOM.render(<Quiz {...data}  />, div)
});

function Quiz(props){
    const [isCorrect, setIsCorrect] = useState(undefined);
    const [isCorrectDelayed, setIsCorrectDelayed] = useState(undefined);


    useEffect(() => {
        if (isCorrect === false) {
            setTimeout(() => {
                setIsCorrect(undefined)
            }, 2600)
        }

        if (isCorrect === true) {
            setTimeout(() => {
                setIsCorrectDelayed(true)
            }, 1000)
        }
    }, [isCorrect])


    function handleAnswer(index){
        if(index=== props.correctAnswer){
           setIsCorrect(true)
        } else{
           setIsCorrect(false)
        }
    }


    return (
        <div className="gcb_block"  style={{backgroundColor: props.bgColor, textAlign:props.theAlignment}} >
            <p>{props.question}</p>
            <ul>
                {props.answers.map(function (answer, index){
                   return (

                       <li className={(isCorrectDelayed === true && index == props.correctAnswer ? "no-click" : "") + (isCorrectDelayed === true && index != props.correctAnswer ? "fade-incorrect": "")} onClick={isCorrect === true ? undefined : () => handleAnswer(index)}>
                           {isCorrectDelayed === true && index == props.correctAnswer && (
                               <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" className="bi bi-check" viewBox="0 0 16 16">
                                   <path d="M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425a.267.267 0 0 1 .02-.022z"/>
                               </svg>
                           )}
                           {isCorrectDelayed === true && index != props.correctAnswer && (
                               <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" className="bi bi-x" viewBox="0 0 16 16">
                                   <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>
                               </svg>
                           )}
                           {answer}
                       </li>

                   )
                })}
            </ul>

            <div className={"correct-message" + (isCorrect === true ? " correct-message--visible" : "" )}>
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor"
                     className="bi bi-emoji-smile" viewBox="0 0 16 16">
                    <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
                    <path
                        d="M4.285 9.567a.5.5 0 0 1 .683.183A3.498 3.498 0 0 0 8 11.5a3.498 3.498 0 0 0 3.032-1.75.5.5 0 1 1 .866.5A4.498 4.498 0 0 1 8 12.5a4.498 4.498 0 0 1-3.898-2.25.5.5 0 0 1 .183-.683zM7 6.5C7 7.328 6.552 8 6 8s-1-.672-1-1.5S5.448 5 6 5s1 .672 1 1.5zm4 0c0 .828-.448 1.5-1 1.5s-1-.672-1-1.5S9.448 5 10 5s1 .672 1 1.5z"/>
                </svg>
                <p>That is correct!</p>
            </div>
            <div className={"incorrect-message" + (isCorrect === false ? " correct-message--visible" : "" )}>
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor"
                     className="bi bi-emoji-frown" viewBox="0 0 16 16">
                    <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
                    <path
                        d="M4.285 12.433a.5.5 0 0 0 .683-.183A3.498 3.498 0 0 1 8 10.5c1.295 0 2.426.703 3.032 1.75a.5.5 0 0 0 .866-.5A4.498 4.498 0 0 0 8 9.5a4.5 4.5 0 0 0-3.898 2.25.5.5 0 0 0 .183.683zM7 6.5C7 7.328 6.552 8 6 8s-1-.672-1-1.5S5.448 5 6 5s1 .672 1 1.5zm4 0c0 .828-.448 1.5-1 1.5s-1-.672-1-1.5S9.448 5 10 5s1 .672 1 1.5z"/>
                </svg>
                <p>Sorry try again. </p>
            </div>


        </div>

    )
}

Гутенберг элемент должен иметь возможнозность выводить для пользователя Вопрос, и варианты ответов. Проблема в том, что на фронтовую часть не передается значение {props.question} не могу понять почему. На бекэ всё хорошо, и блоковый элемент перезаписывает состояние question Как можно понять в чём причина поломки ?


Ответы (0 шт):