我有一个块,允许用户在编辑模式下输入脚本,然后将该脚本发送到REST端点,该端点返回WP_Post
表示随后显示给用户的媒体文件。REST端点可能需要几秒钟(甚至几分钟)才能发送回复,因此我希望以异步方式进行更新,并在用户等待时显示微调器。
问题是,即使在REST端点返回其值之后,微调器也会无限期显示。我不确定我做错了什么。以下是我的(缩写)块代码:
( function( wp ) {
var registerBlockType = wp.blocks.registerBlockType;
var withSelect = wp.data.withSelect;
var el = wp.element.createElement;
var Component = wp.element.Component;
var Spinner = wp.components.Spinner;
var __ = wp.i18n.__;
function getEditComponent( blockName, blockTitle ) {
return class extends Component {
render() {
const { mediaFile, isSelected, className, attributes, setAttributes } = this.props;
const { script } = attributes;
// Check if the mediaFile has been populated via REST yet.
const hasMedia = Array.isArray( mediaFile ) && mediaFile.length;
if ( isSelected ) {
// Show edit textarea.
return el(
\'div\',
{ className },
el(
\'label\',
null,
__( \'Script:\', \'my-textdomain\' ),
el(
\'textarea\',
{
onChange: ( event ) => {
// Update script attribute as it is typed.
setAttributes( { script: event.target.value } );
},
value: script,
style: {
width: \'100%\'
},
spellCheck: false,
placeholder: __( \'Enter script\', \'my-textdomain\' ),
}
)
)
);
} else {
if ( ! hasMedia ) {
return (
el(
Placeholder,
{
label: __( \'label\', \'my-textdomain\' ),
},
// Display spinner until mediaFile has been returned from REST.
! Array.isArray( mediaFile ) ? Spinner() : __( \'Media is being generated.\', \'my-textdomain\' ),
)
);
}
return el(
\'img\',
{
src: mediaFile.guid || \'\', // Display mediaFile\'s URL.
}
);
}
}
};
};
const name = \'my-namespace/my-block\';
const title = __( \'Script\', \'my-textdomain\' );
const edit = getEditComponent( name, title );
registerBlockType( name, {
// Various properties here, like title, description, etc...
edit: withSelect( ( select, props ) => {
const { attributes } = props;
const { script } = attributes;
// Get media file using script.
const mediaFile = wp.apiFetch(
{
path: \'/my-api-namespace/v1/do-thing\',
method: \'POST\',
data: {
script: script,
},
}
);
return {
mediaFile,
};
} )( edit ),
save: null, // not shown here
} );
} )(
window.wp
);
edit函数是API获取的地方,它被写入edit类的属性中
mediaFile
. 最初,这是一种
Promise
返回人
wp.apiFetch
, 但最终(我认为)它会成为这种获取的结果(在我的例子中是a
WP_Post
阵列)。
编辑类的render
函数检查是否mediaFile
是否填充,并决定是显示“加载”微调器还是显示实际的媒体文件图像。
最合适的回答,由SO网友:Sean 整理而成
我通过阅读React docs. 现在,我使用编辑组件自己的状态来存储从REST检索到的媒体文件,发出REST请求的函数现在位于编辑组件中。我不需要withSelect
再也没有了。
与第一篇文章中的方法相比,这是一种更好的方法,因为它涉及组件设置自己的状态。从组件外部设置组件状态为not allowed, 建议您与组件共享外部范围内的变量,然后更新该变量。此外,传递给组件的属性应该是不可变的。在问题中mediaFile
属性不是不可变的。
这些要点引导我在编辑组件本身中使用其自身的状态实现REST请求。它现在从REST获取媒体文件,并在收到响应时更新其状态。然后,状态由render
函数检查媒体文件是否可用,如果不可用,则显示微调器。这个setState
电话由apiFetch.then
函数强制重新渲染,以便在检索图像时显示图像。
以下是(缩写)工作块:
( function( wp ) {
var registerBlockType = wp.blocks.registerBlockType;
var withSelect = wp.data.withSelect;
var el = wp.element.createElement;
var Component = wp.element.Component;
var Spinner = wp.components.Spinner;
var __ = wp.i18n.__;
function getEditComponent( blockName, blockTitle ) {
return class extends Component {
constructor( props ) {
super( props );
this.state = {
mediaFile: {},
};
}
getPlot() {
const { attributes } = this.props;
const { script } = attributes;
if ( this.gettingPlot ) {
return;
}
this.gettingPlot = true;
wp.apiFetch(
{
path: \'/my-api-namespace/v1/do-thing\',
method: \'POST\',
data: {
script: script,
},
}
).then(
( media ) => {
this.setState(
{
mediaFile: media,
}
);
this.gettingPlot = false;
}
).catch(
() => {
this.gettingPlot = false;
}
);
}
render() {
const { isSelected, className, attributes, setAttributes } = this.props;
const { script } = attributes;
let mediaFile = this.state.mediaFile;
const hasMedia = ( mediaFile != null && Object.keys( mediaFile ).length );
if ( isSelected ) {
return el(
\'div\',
{ className },
el(
\'label\',
null,
__( \'Script:\', \'my-textdomain\' ),
el(
\'textarea\',
{
onChange: ( event ) => {
// Update script attribute as it is typed.
setAttributes( { script: event.target.value } );
},
value: script,
style: {
width: \'100%\'
},
spellCheck: false,
placeholder: __( \'Enter script\', \'my-textdomain\' ),
}
)
)
);
} else {
this.getPlot();
if ( ! hasMedia ) {
return (
el(
Placeholder,
{
label: __( \'label\', \'my-textdomain\' ),
},
// Display spinner until media file can be read.
Spinner(),
)
);
}
return el(
\'img\',
{
src: mediaFile.guid || \'\',
}
);
}
}
};
};
const name = \'my-namespace/my-block\';
const title = __( \'Script\', \'my-textdomain\' );
const edit = getEditComponent( name, title );
registerBlockType( name, {
// Various properties here, like title, description, etc...
edit,
save: null, // not shown here
} );
} )(
window.wp
);