admin管理员组文章数量:1192554
Rephrased the question on August 9th.
This is my first attempt to work with Wordpress blocks and also my first time working with React.
The code below adds the possibility to conditionally show blocks.
My question is related to the "select pages" section, or the "useSelect".
I show a list of pages which have been selected previously. I also show a list of pages based on a search. Whenever someone selects a page I move the checkbox from the search list to the selected list.
This works great except when I save the page/post whatever. Somehow when the "initialSelectedPages" gets rendered it uses the old attributes... I have to refresh the page, or re-select the block in order to show the the correct updated list.
But I have no idea why. Any ideas?
Also, as this is my first React code, any feedback is welcome!
This is my code how I load the js:
add_action( 'enqueue_block_editor_assets', function() {
wp_register_script(
'sim-block-filter',
plugins_url('blocks/build/index.js', __DIR__),
[ 'wp-blocks', 'wp-dom', 'wp-dom-ready', 'wp-edit-post' ],
STYLE_VERSION
);
wp_enqueue_script( 'sim-block-filter' );
});
This is the js
const { __ } = wp.i18n;
const { createHigherOrderComponent } = wppose;
const { Fragment } = wp.element;
const { InspectorControls } = wp.blockEditor;
const { PanelBody, ToggleControl, CheckboxControl } = wpponents;
import { SearchControl, Spinner, __experimentalInputControl as InputControl } from '@wordpress/components';
import {useState, useEffect } from "@wordpress/element";
import { useSelect } from '@wordpress/data';
import { store as coreDataStore } from '@wordpress/core-data';
import { decodeEntities } from '@wordpress/html-entities';
// Add attributes
function addFilterAttribute(settings) {
if (typeof settings.attributes !== 'undefined') {
settings.attributes = Object.assign(settings.attributes, {
hideOnMobile: {
type: 'boolean',
},
onlyOnHomePage: {
type: 'boolean',
},
onlyLoggedIn: {
type: 'boolean',
},
onlyOn: {
type: 'array'
},
phpFilters: {
type: 'array'
}
});
}
return settings;
}
wp.hooks.addFilter(
'blocks.registerBlockType',
'sim/block-filter-attribute',
addFilterAttribute
);
// Add controls to panel
const blockFilterControls = createHigherOrderComponent((BlockEdit) => {
return ( props ) => {
const { attributes, setAttributes, isSelected } = props;
// Only work on selected blocks
if(!isSelected){
return (
<Fragment>
<BlockEdit { ...props } />
</Fragment>
);
}
//console.log(attributes.onlyOn)
if(attributes.onlyOn == undefined){
attributes.onlyOn = [];
}
/** FUNCTIONS */
const [ searchTerm, setSearchTerm ] = useState( '' );
// Selected page list
const { initialSelectedPages, selectedPagesResolved} = useSelect(
( select) => {
// Find all selected pages
const selectedPagesArgs = [ 'postType', 'page', {include : attributes.onlyOn} ];
//console.log(attributes.onlyOn);
return {
initialSelectedPages: select( coreDataStore ).getEntityRecords(
...selectedPagesArgs
),
selectedPagesResolved: select( coreDataStore ).hasFinishedResolution(
'getEntityRecords',
selectedPagesArgs
)
};
},
[]
);
// Search page list
const { pages, pagesResolved } = useSelect(
( select) => {
// do not show results if not searching
if ( !searchTerm ) {
return{
pages: true,
pagesResolved: []
}
}
// find all pages excluding the already selected pages
const query = {
exclude : attributes.onlyOn,
search : searchTerm
};
const pagesArgs = [ 'postType', 'page', query ];
return {
pages: select( coreDataStore ).getEntityRecords(
...pagesArgs
),
pagesResolved: select( coreDataStore ).hasFinishedResolution(
'getEntityRecords',
pagesArgs
)
};
},
[ searchTerm ]
);
const PageSelected = function(checked){
let newPages = [...attributes.onlyOn];
if(checked){
// Add to stored page ids
newPages.push(this);
// Add to selected pages list
let newSelectedPages = [...selectedPages];
newSelectedPages.push(pages.find( p => p.id == this));
setSelectedPages(newSelectedPages);
}else{
newPages = newPages.filter( p => {return p != this} );
}
setAttributes({onlyOn: newPages});
}
const GetSelectedPagesControls = function(){
if(attributes.onlyOn.length > 0){
return (
<>
<i> {__('Currently selected pages', 'sim')}:</i>
<br></br>
<BuildCheckboxControls hasResolved={ selectedPagesResolved } items={initialSelectedPages} showNoResults={false}/>
</>
);
}else{
return '';
}
}
const BuildCheckboxControls = function({ hasResolved, items, showNoResults= true }){
if ( ! hasResolved ) {
return(
<>
<Spinner />
<br></br>
</>
);
}
if ( ! items?.length ) {
if(showNoResults){
if ( !searchTerm ) {
return '';
}
return <div> {__('No search results', 'sim')}</div>;
}
return '';
}
return items?.map( ( page ) => {
return (<CheckboxControl
label = {decodeEntities( page.title.rendered )}
onChange = {PageSelected.bind(page.id)}
checked = {attributes.onlyOn.includes(page.id)}
/>)
} )
}
/** HOOKS */
const [ selectedPages, setSelectedPages ] = useState( [] );
const [ selectedPagesControls, setSelectedPagesControls ] = useState( GetSelectedPagesControls() );
// Update selectedPagesControls on page resolve
useEffect(() => {
setSelectedPages(initialSelectedPages);
}, [ selectedPagesResolved ]);
// Update selectedPagesControls on check/uncheck
useEffect(() => {
setSelectedPages( selectedPages.filter( p => {return attributes.onlyOn.includes(p.id)} ));
}, [ attributes.onlyOn ]);
useEffect(
() => {
setSelectedPagesControls(BuildCheckboxControls({hasResolved: selectedPagesResolved, items: selectedPages, showNoResults: false}));
},
[selectedPages]
);
return (
<Fragment>
<BlockEdit { ...props } />
<InspectorControls>
<PanelBody title={ __( 'Block Visibility' ) }>
<strong>{__('Select pages', 'sim')}</strong><br></br>
{__('Select pages you want this widget to show on', 'sim')}.<br></br>
{__('Leave empty for all pages', 'sim')}<br></br>
<br></br>
{selectedPagesControls}
<i>{__('Use searchbox below to search for more pages to include', 'sim')}</i>
< SearchControl onChange={ setSearchTerm } value={ searchTerm } />
< BuildCheckboxControls hasResolved= {pagesResolved} items= {pages} />
</PanelBody>
</InspectorControls>
</Fragment>
);
};
}, 'blockFilterControls');
wp.hooks.addFilter(
'editor.BlockEdit',
'sim/block-filter-controls',
blockFilterControls
);
Rephrased the question on August 9th.
This is my first attempt to work with Wordpress blocks and also my first time working with React.
The code below adds the possibility to conditionally show blocks.
My question is related to the "select pages" section, or the "useSelect".
I show a list of pages which have been selected previously. I also show a list of pages based on a search. Whenever someone selects a page I move the checkbox from the search list to the selected list.
This works great except when I save the page/post whatever. Somehow when the "initialSelectedPages" gets rendered it uses the old attributes... I have to refresh the page, or re-select the block in order to show the the correct updated list.
But I have no idea why. Any ideas?
Also, as this is my first React code, any feedback is welcome!
This is my code how I load the js:
add_action( 'enqueue_block_editor_assets', function() {
wp_register_script(
'sim-block-filter',
plugins_url('blocks/build/index.js', __DIR__),
[ 'wp-blocks', 'wp-dom', 'wp-dom-ready', 'wp-edit-post' ],
STYLE_VERSION
);
wp_enqueue_script( 'sim-block-filter' );
});
This is the js
const { __ } = wp.i18n;
const { createHigherOrderComponent } = wp.compose;
const { Fragment } = wp.element;
const { InspectorControls } = wp.blockEditor;
const { PanelBody, ToggleControl, CheckboxControl } = wp.components;
import { SearchControl, Spinner, __experimentalInputControl as InputControl } from '@wordpress/components';
import {useState, useEffect } from "@wordpress/element";
import { useSelect } from '@wordpress/data';
import { store as coreDataStore } from '@wordpress/core-data';
import { decodeEntities } from '@wordpress/html-entities';
// Add attributes
function addFilterAttribute(settings) {
if (typeof settings.attributes !== 'undefined') {
settings.attributes = Object.assign(settings.attributes, {
hideOnMobile: {
type: 'boolean',
},
onlyOnHomePage: {
type: 'boolean',
},
onlyLoggedIn: {
type: 'boolean',
},
onlyOn: {
type: 'array'
},
phpFilters: {
type: 'array'
}
});
}
return settings;
}
wp.hooks.addFilter(
'blocks.registerBlockType',
'sim/block-filter-attribute',
addFilterAttribute
);
// Add controls to panel
const blockFilterControls = createHigherOrderComponent((BlockEdit) => {
return ( props ) => {
const { attributes, setAttributes, isSelected } = props;
// Only work on selected blocks
if(!isSelected){
return (
<Fragment>
<BlockEdit { ...props } />
</Fragment>
);
}
//console.log(attributes.onlyOn)
if(attributes.onlyOn == undefined){
attributes.onlyOn = [];
}
/** FUNCTIONS */
const [ searchTerm, setSearchTerm ] = useState( '' );
// Selected page list
const { initialSelectedPages, selectedPagesResolved} = useSelect(
( select) => {
// Find all selected pages
const selectedPagesArgs = [ 'postType', 'page', {include : attributes.onlyOn} ];
//console.log(attributes.onlyOn);
return {
initialSelectedPages: select( coreDataStore ).getEntityRecords(
...selectedPagesArgs
),
selectedPagesResolved: select( coreDataStore ).hasFinishedResolution(
'getEntityRecords',
selectedPagesArgs
)
};
},
[]
);
// Search page list
const { pages, pagesResolved } = useSelect(
( select) => {
// do not show results if not searching
if ( !searchTerm ) {
return{
pages: true,
pagesResolved: []
}
}
// find all pages excluding the already selected pages
const query = {
exclude : attributes.onlyOn,
search : searchTerm
};
const pagesArgs = [ 'postType', 'page', query ];
return {
pages: select( coreDataStore ).getEntityRecords(
...pagesArgs
),
pagesResolved: select( coreDataStore ).hasFinishedResolution(
'getEntityRecords',
pagesArgs
)
};
},
[ searchTerm ]
);
const PageSelected = function(checked){
let newPages = [...attributes.onlyOn];
if(checked){
// Add to stored page ids
newPages.push(this);
// Add to selected pages list
let newSelectedPages = [...selectedPages];
newSelectedPages.push(pages.find( p => p.id == this));
setSelectedPages(newSelectedPages);
}else{
newPages = newPages.filter( p => {return p != this} );
}
setAttributes({onlyOn: newPages});
}
const GetSelectedPagesControls = function(){
if(attributes.onlyOn.length > 0){
return (
<>
<i> {__('Currently selected pages', 'sim')}:</i>
<br></br>
<BuildCheckboxControls hasResolved={ selectedPagesResolved } items={initialSelectedPages} showNoResults={false}/>
</>
);
}else{
return '';
}
}
const BuildCheckboxControls = function({ hasResolved, items, showNoResults= true }){
if ( ! hasResolved ) {
return(
<>
<Spinner />
<br></br>
</>
);
}
if ( ! items?.length ) {
if(showNoResults){
if ( !searchTerm ) {
return '';
}
return <div> {__('No search results', 'sim')}</div>;
}
return '';
}
return items?.map( ( page ) => {
return (<CheckboxControl
label = {decodeEntities( page.title.rendered )}
onChange = {PageSelected.bind(page.id)}
checked = {attributes.onlyOn.includes(page.id)}
/>)
} )
}
/** HOOKS */
const [ selectedPages, setSelectedPages ] = useState( [] );
const [ selectedPagesControls, setSelectedPagesControls ] = useState( GetSelectedPagesControls() );
// Update selectedPagesControls on page resolve
useEffect(() => {
setSelectedPages(initialSelectedPages);
}, [ selectedPagesResolved ]);
// Update selectedPagesControls on check/uncheck
useEffect(() => {
setSelectedPages( selectedPages.filter( p => {return attributes.onlyOn.includes(p.id)} ));
}, [ attributes.onlyOn ]);
useEffect(
() => {
setSelectedPagesControls(BuildCheckboxControls({hasResolved: selectedPagesResolved, items: selectedPages, showNoResults: false}));
},
[selectedPages]
);
return (
<Fragment>
<BlockEdit { ...props } />
<InspectorControls>
<PanelBody title={ __( 'Block Visibility' ) }>
<strong>{__('Select pages', 'sim')}</strong><br></br>
{__('Select pages you want this widget to show on', 'sim')}.<br></br>
{__('Leave empty for all pages', 'sim')}<br></br>
<br></br>
{selectedPagesControls}
<i>{__('Use searchbox below to search for more pages to include', 'sim')}</i>
< SearchControl onChange={ setSearchTerm } value={ searchTerm } />
< BuildCheckboxControls hasResolved= {pagesResolved} items= {pages} />
</PanelBody>
</InspectorControls>
</Fragment>
);
};
}, 'blockFilterControls');
wp.hooks.addFilter(
'editor.BlockEdit',
'sim/block-filter-controls',
blockFilterControls
);
Share
Improve this question
edited Aug 11, 2022 at 12:28
Tsjippy
asked Aug 6, 2022 at 7:03
TsjippyTsjippy
113 bronze badges
4
- its start is promising. Good question and well formatted. But don't be seen as a BOT... Enter a username and update your profile... Soon someone will comment on your question. I don't talk about it because I don't have the domain for it. Hug – PauloBoaventura Commented Aug 6, 2022 at 11:42
- He is seen by the system how? CSS, PHP or Javascript... If it's JavaScript you can just quote it and put it to load below the page. But I've never heard of optimizing React... You should just put it to load at the correct time on the page. So that it doesn't interrupt the loading of it... As I said... Handle it as if it were CSS or Javascript... Look for more about it. – PauloBoaventura Commented Aug 6, 2022 at 11:47
- thank you, I have updated the question – Tsjippy Commented Aug 9, 2022 at 10:35
- 1 I'm a little confused, your question title talks about making your react code faster and asking for optimisations, but then I read your questions text it's instead asking about stale/old attributes and having to refresh the page. Can you make sure your question is consistent? Questions here should be clear and specific – Tom J Nowell ♦ Commented Aug 11, 2022 at 12:32
1 Answer
Reset to default 0Of course it never changes, because you told it that it never changes:
// Selected page list
const { initialSelectedPages, selectedPagesResolved} = useSelect(
( select) => {
....
},
----->[] <-----
);
You declared the dependencies as an empty array, and empty arrays won't change, so this hook won't update when your attributes update because you didn't specify the attributes that were going to update.
E.g.
const { foo } = useSelect(
( select ) => {
return { foo: bar+1 };
},
[ bar ]
);
Here, foo will have the value of bar + 1
. That function will not run until the contents of the dependency array changed. This avoids it constantly running. The only reason foo
changes when bar
changes is because I declared bar
as a dependency.
So when you do this:
const selectedPagesArgs = [ 'postType', 'page', {include : attributes.onlyOn} ];
It has no idea that when attributes.onlyOn
changes it has to redo this, because you did not declare it in the list of dependencies.
Note that this is similar if not the same semantics as useEffect
.
Here is the official documentation with examples and explanations:
https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/#useselect
本文标签: block editorCan this react script be optimized How to make it faster
版权声明:本文标题:block editor - Can this react script be optimized? How to make it faster 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738467052a2088367.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论