我构建了一个定制的Gutenberg块,以显示一个名为story
. 大多数事情最终都很顺利,故事通过服务器端渲染(ServerSideRendering)按需要显示出来。要选择要显示的故事,侧边栏中有一个单选按钮列表。
我想要的:-从单选按钮中选择一个故事后,我希望显示的故事刷新。从一些例子中,我相信这可以解决withSelect
或useSelect
或者类似的东西。但我不知道该如何在我的案件中使用它们。
当story_id
如果编辑函数的story_id
.
代码如下:
/**
* Story-Block: osf-blocks-story
*
* Gives back a rendered story (list of images with text & title) after selecting from the left block sidebar
*
* based on create-guten-block
*/
import \'./style.scss\';
import \'./editor.scss\';
import { registerBlockType } from \'@wordpress/blocks\';
import { ServerSideRender, RadioControl, PanelBody } from \'@wordpress/components\';
import { InspectorControls } from \'@wordpress/block-editor\';
import { Component, Fragment } from \'@wordpress/element\';
import { useSelect, withSelect } from \'@wordpress/data\';
let $ = jQuery;
// short for console.log
function cl(words) { console.log(\'drx-osf-story, block.js: \' + words); }
// to get more object infos than console.log(obj + \'some comment\');
function ol(object, words=\'\') {
cl(words + \': \\\\/\');
console.log(object);
}
// Represents a single story, i.e. a collection of parts with image, short text and possibly a title
class Story extends Component {
constructor(props) {
super(props);
this.state = {
story_id: props.story_id
}
}
render() {
return (
<ServerSideRender
block="osf-blocks/story"
attributes={this.state}
/>
)
}
}
// Represents a list of radiobuttons to select one of all stories
class StoriesListControl extends Component {
constructor(props) {
super(props);
this.state = {
changeHandler: props.changeHandler,
story_id: props.story_id,
options: props.options
};
}
render() {
return (
<InspectorControls>
<PanelBody title=\'Story auswählen:\'>
<RadioControl
label="Wähle, welche Story hier eingefügt werden soll."
help="Die Story muss vorher über das Story-Interface angelegt worden sein."
selected={ this.state.story_id }
options={ this.state.options }
onChange={ this.state.changeHandler }
/>
</PanelBody>
</InspectorControls>
);
}
};
// Registering the block
registerBlockType(\'osf-blocks/story\', {
title: \'Story\' ,
icon: \'images-alt2\',
category: \'widgets\',
attributes: {
story_id: {
type: \'string\'
}
},
keywords: [
\'osf-blocks-story\',
\'Story\',
\'Stories\'
],
edit: (props) => {
// what to do with withSelect/useSelect here??
const {
attributes: { story_id },
setAttributes
} = props;
// called, if a radiobutton gets selected
const changeHandler = (new_story_id) => {
setAttributes({ story_id: new_story_id });
};
// fetching the list of all stories (custom post type) from server
const getStoriesList = () => {
let answer;
$.ajax({
url: \'/wp-admin/admin-ajax.php\',
type: \'POST\',
data: {
action: \'stories_list\'
},
async: false,
timeout: 3000 // ms
}).done((rspns) => {
// removing trailing 0 - what does it mean?
answer = { status: \'success\', result: JSON.parse(rspns.substr(0, rspns.length - 1)) };
}).fail((xhr, status) => {
cl(\'request failed: \' + status);
ol(xhr);
answer = { status:\'fail\', log: status }
});
return answer;
};
// tie it all together
let response = getStoriesList();
let output;
if ( \'success\' == response.status) {
// AJAX for storieslist succeeded
ol(response, \'response\');
output = (
<Fragment>
<StoriesListControl
changeHandler={ changeHandler }
story_id={ story_id }
options={ response.result }
/>
<div className="story-container">
<div id={ "story" + story_id } className="story-preview container">
<Story story_id={ story_id } />
</div>
</div>
</Fragment>
);
}
else if (\'fail\' == response.status) {
// AJAX failed
output = (
<Fragment>
<div className="story-container">
<p>No connection to the server: { response.log }</p>
</div>
</Fragment>
);
}
return output;
},
save: (props) => {
return null;
}
});
SO网友:bosco
在本例中,您将异步jQuery AJAX调用视为一个同步函数,从而导致getStoriesList()
持续返回undefined
函数在调度HTTP请求后立即返回;正在尝试访问response.status
应持续投掷ReferenceError: response is not defined
.
在几乎所有情况下,通过古腾堡的各种数据存储上提供的选择器访问数据更为理想-如果REST API在存储中丢失或未初始化,许多选择器将从REST API异步获取数据,然后更新各自的状态,并自动触发已订阅该状态更改的每个组件的更新,使用withSelect()
或useSelect()
.
在这里绕过Gutenberg的数据流,您无法在使用新数据时更新组件useSelect()
或withSelect()
因为AJAX处理程序的响应不会触发存储中的状态更新,因此存储不会通知任何订阅的函数或组件。当前的实现还导致在每次呈现组件时调度HTTP请求,这是不必要的。
在这种情况下getStoriesList()
返回CPT帖子列表的函数和关联的AJAX处理程序应简洁地替换为getEntityRecords()
上的选择器core
数据存储。我们可以通过返回的对象访问核心数据存储的选择器select( \'core\' )
. 将该访问包装在useSelect()
钩子创建对核心存储的订阅,重新呈现edit()
每当所选数据的状态发生更改时自动执行。
此外,第二个论点useSelect()
是一个依赖项数组。通过添加story_id
对于它,我们可以缓存帖子列表,并且只有在story_id
更改。
// Registering the block
registerBlockType(\'osf-blocks/story\', {
//...
edit: (props) => {
const {
attributes: { story_id },
setAttributes
} = props;
const stories = useSelect(
select => select( \'core\' ).getEntityRecords(
\'postType\',
\'story\',
{ id: story_id }
),
[ story_id ]
);
// called, if a radiobutton gets selected
const setStoryID = ( story_id ) => setAttributes( { story_id } );
return (
<Fragment>
<StoriesListControl
changeHandler={ setStoryID }
story_id={ story_id }
options={ stories }
/>
<div className="story-container">
<div id={ `story${ story_id }` } className="story-preview-container">
<Story story_id={ story_id } />
</div>
</div>
</Fragment>
);
}
// ...
});