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 Как можно понять в чём причина поломки ?