Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setAttributes is slow resulting in retrieving attributes old values #16058

Closed
bomsn opened this issue Jun 9, 2019 · 3 comments
Closed

setAttributes is slow resulting in retrieving attributes old values #16058

bomsn opened this issue Jun 9, 2019 · 3 comments
Labels
[Feature] Block API API that allows to express the block paradigm. Needs Technical Feedback Needs testing from a developer perspective. [Type] Help Request Help with setup, implementation, or "How do I?" questions.

Comments

@bomsn
Copy link

bomsn commented Jun 9, 2019

Describe the bug
When using setAttributes in the edit object it's not updating attributes right away. This result in the old values being returned if you tried to retrieve from dataset right after calling setAttributes

To reproduce
Steps to reproduce the behavior:

  1. Render the following:
    <Fragment>
      <InspectorControls>
            <PanelBody
                title="Date & Time"
                icon=""
                initialOpen={ false }
            >
                <PanelRow>
                <DateTimePicker
                    currentDate={ attributes.datetime }
                    onChange={ ( val ) => onUpdateDate( val ) }
                    is12Hour={ true }
                />
                </PanelRow>
            </PanelBody>
     <InspectorControls>
     <div className={ 'datetimediv' } data-datetime={datetime}></div>
</Fragment>
  1. Use the update function like this:
  const onUpdateDate = ( dateTime ) => {
      var newDateTime = moment(dateTime).format( 'YYYY-MM-DD HH:mm' );
      setAttributes( { datetime: newDateTime } );
      // This will return the old value not the one that we just set above
      console.log( document.getElementsByClassName('datetimediv')[0].dataset.datetime );
  };

Expected behavior
If we used the dataset property on the element that we just updated it should return the updated value.

Workaround
If you do this it will return the correct value

  const onUpdateDate = ( dateTime ) => {
      var newDateTime = moment(dateTime).format( 'YYYY-MM-DD HH:mm' );
      setAttributes( { datetime: newDateTime } );
      setTimeout(function(){
          console.log( document.getElementsByClassName('datetimediv')[0].dataset.datetime );
      }, 100);
  };

@swissspidy swissspidy added the [Feature] Block API API that allows to express the block paradigm. label Jun 10, 2019
@swissspidy
Copy link
Member

I think what you are describing here is not slowness nor a bug, but the asynchronous nature of JavaScript and its event loop, and in this particular instance the data store.

In your particular example, why are you accessing the DOM to get the value when you already have newDateTime?

@bomsn
Copy link
Author

bomsn commented Jun 10, 2019

@swissspidy I think for this reason there need to be a listener after setAttributes is done or a way to initiate some action after it's complete.

And for your question regarding the DOM, that's not actually the code I'm using, it's just an example. I created a countdown block, after setAttributes I'm calling a function from frontend.js to update countdown different values and apply different functionality.

Why I don't pass the variable to the function I'm calling?
Because there is a large number of attributes and I need to run a specific function that searches the DOM for this data, I can't pass the new attribute value because the same function is responsible on frontend view.

You can see my full code here: countdown-pro-for-gutenberg

@swissspidy swissspidy added [Type] Help Request Help with setup, implementation, or "How do I?" questions. Needs Technical Feedback Needs testing from a developer perspective. labels Jun 10, 2019
@aduth
Copy link
Member

aduth commented Jun 10, 2019

Previously: #5596

This is working as intended. The DOM is not intended to serve as a source of truth. Your block components should respond to changes in the incoming attributes prop.

There is more information in #5596, but this is also simpler these days with the introduction of React's useEffect (available at wp.element.useEffect):

https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect

Following the code example there, you could define props.attributes.datetime in the second argument array, and the callback would be triggered any time it changes.

@aduth aduth closed this as completed Jun 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm. Needs Technical Feedback Needs testing from a developer perspective. [Type] Help Request Help with setup, implementation, or "How do I?" questions.
Projects
None yet
Development

No branches or pull requests

3 participants