3

I'm creating the block settings (attributes) as an Input Box which on change go to the server side and request an API.

When I enter characters in Input Box. Example: Mango, it makes several API requests because of the onChange. I wanted to debounce until the user finishes typing.

<TextControl
                
  key="music-search-input-control"
  label={ __( 'Search', 'music-player' ) }
  value = {theme}
  onChange={ selectTheme }
/>

function selectTheme( value ) {
    setAttributes( { theme: value } );
}

Now, with the ServerSideRender - it fires on Change.

 <ServerSideRender
       key="music-player-server-side-renderer"
       block="music-player/music-player-selector"
       attributes={ props.attributes }
 />

Attributes on edit

const {
        attributes: {
            theme = '',
        },

    setAttributes
 } = props;

How to debounce the input value, so it won't go to server side until user finishes typing?

1 Answer 1

2

You can use useDebounce or debounce (you also have throttle) in package @wordpress/compose

I did not test the code, but something like that:

import { useDebounce } '@wordpress/compose';

function Edit({attributes, setAttributes}) {
  debounced_selectTheme = useDebounce(selectTheme, milliseconds, options)

  <TextControl                
    key="music-search-input-control"
    label={ __( 'Search', 'aawp' ) }
    value = {theme}
    /* you have a typo in code in following line */
    onChange= { debounced_selectTheme }
  />
}

There is also a question why are you using ServerSideRender. Unless you use something that changes in database outside of post, so you need PHP to catch most recent version, there is no need for that. You can use selectors to get media file names etc.

EDIT: You can't use ServerSideRender in order for debounce to work for simple reason: setAttributes update TextControl value and in turn, TextControl is refreshed and updated only when attributes are changed. It means that if TextControl is refreshed, ServerSideRender will be refreshed as well, which is slow.

Now, you can use some heavy React tweaking by introducing useState and defining one variable, called let's say "refresh" and introduce memoizing with useCallback hook, where you would memoize ServerSideRender to refresh only when refresh is updated like so:

// create a function here to create a component which will be memoized
const MyServerSideRender = () => (
     <ServerSideRender
       key="music-player-server-side-renderer"
       block="music-player/music-player-selector"
       attributes={ proxyAttributes }
     />
);
[proxyAttributes, setProxyAttributes] = useState(attributes);
MemoizedServerSideRender = useCallback(MyServerSideRender, [proxyAttributes]);

// in your debounced function set proxyAttributes and in TextControl  onChange use setAttributes
debounced_selectTheme = useDebounce(selectTheme, milliseconds, options)
function selectTheme( value ) {
    setProxyAttributes( {...attributes} );
}

// return part of edit function:
<TextControl
                
  key="music-search-input-control"
  label={ __( 'Search', 'music-player' ) }
  value = {theme}
  onChange={ theme => { setAttributes( { theme } ); debounced_selectTheme() }
/>
<MemoizedServerSideRender />

However, I am not 100% sure if this would work without problems. You see, this is a very complicated approach. I think it would be much easier not to use ServerSideRender if that could be avoided. Then all this is not needed. Ask if you need additional assistance.

EDIT 2: You can still use PHP render callback if you must, but not use ServerSideRender in Edit function and instead recode this which you show in PHP in React. This is the way some core blocks are done.

10
  • It actually debounced the onchange. So, I enter a character, it took a few time until I'm allowed to enter another character.
    – micky
    Commented Dec 16, 2022 at 8:21
  • You are right. I will update the answer
    – Lovor
    Commented Dec 16, 2022 at 11:17
  • I just updated answer - just to notice you by this comment
    – Lovor
    Commented Dec 16, 2022 at 11:50
  • Hi @Lovor, Thanks for sharing the details. Yes, it looks complicated. I need the render_callback where PHP returns the contents of the block to preview on the block editor depending on the attribute (value of the input box). I see that ServerSideRender seems like a legacy approach. Is there an alternative similar to that?
    – micky
    Commented Dec 17, 2022 at 4:02
  • I do not know details of what you want to output as HTML - perhaps it can be coded in JSX? Share the details and I can help
    – Lovor
    Commented Dec 17, 2022 at 19:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.