diff --git a/packages/block-editor/src/components/provider/index.js b/packages/block-editor/src/components/provider/index.js
index 6d06246ca9170..fe1dc7630b2ae 100644
--- a/packages/block-editor/src/components/provider/index.js
+++ b/packages/block-editor/src/components/provider/index.js
@@ -1,139 +1,88 @@
/**
* WordPress dependencies
*/
-import { Component } from '@wordpress/element';
-import { withDispatch } from '@wordpress/data';
-import { compose } from '@wordpress/compose';
+import { useEffect, useRef } from '@wordpress/element';
+import { useSelect, useDispatch } from '@wordpress/data';
/**
* Internal dependencies
*/
import withRegistryProvider from './with-registry-provider';
-class BlockEditorProvider extends Component {
- componentDidMount() {
- this.props.updateSettings( this.props.settings );
- this.props.resetBlocks( this.props.value );
- this.attachChangeObserver( this.props.registry );
- }
+function BlockEditorProvider( {
+ settings,
+ value,
+ children,
+ onChange = () => {},
+ onInput = () => {},
+} ) {
+ const { updateSettings, resetBlocks } = useDispatch( 'core/block-editor' );
- componentDidUpdate( prevProps ) {
- const {
- settings,
- updateSettings,
- value,
- resetBlocks,
- registry,
- } = this.props;
-
- if ( settings !== prevProps.settings ) {
- updateSettings( settings );
- }
-
- if ( registry !== prevProps.registry ) {
- this.attachChangeObserver( registry );
- }
-
- if ( this.isSyncingOutcomingValue ) {
- this.isSyncingOutcomingValue = false;
- } else if ( value !== prevProps.value ) {
- this.isSyncingIncomingValue = true;
- resetBlocks( value );
- }
- }
-
- componentWillUnmount() {
- if ( this.unsubscribe ) {
- this.unsubscribe();
- }
- }
-
- /**
- * Given a registry object, overrides the default dispatch behavior for the
- * `core/block-editor` store to interpret a state change and decide whether
- * we should call `onChange` or `onInput` depending on whether the change
- * is persistent or not.
- *
- * This needs to be done synchronously after state changes (instead of using
- * `componentDidUpdate`) in order to avoid batching these changes.
- *
- * @param {WPDataRegistry} registry Registry from which block editor
- * dispatch is to be overriden.
- */
- attachChangeObserver( registry ) {
- if ( this.unsubscribe ) {
- this.unsubscribe();
- }
+ useEffect( () => {
+ updateSettings( settings );
+ }, [ settings ] );
+ const { blocks, isPersistent, isIgnored } = useSelect( ( select ) => {
const {
getBlocks,
isLastBlockChangePersistent,
__unstableIsLastBlockChangeIgnored,
- } = registry.select( 'core/block-editor' );
+ } = select( 'core/block-editor' );
- let blocks = getBlocks();
- let isPersistent = isLastBlockChangePersistent();
-
- this.unsubscribe = registry.subscribe( () => {
- const {
- onChange,
- onInput,
- } = this.props;
- const newBlocks = getBlocks();
- const newIsPersistent = isLastBlockChangePersistent();
- if (
- newBlocks !== blocks && (
- this.isSyncingIncomingValue ||
- __unstableIsLastBlockChangeIgnored()
- )
- ) {
- this.isSyncingIncomingValue = false;
- blocks = newBlocks;
- isPersistent = newIsPersistent;
- return;
+ return {
+ blocks: getBlocks(),
+ isPersistent: isLastBlockChangePersistent(),
+ isIgnored: __unstableIsLastBlockChangeIgnored(),
+ };
+ } );
+
+ const previousBlocks = useRef( blocks );
+ const previousIsPersistent = useRef( isPersistent );
+ const isSyncingIncomingValue = useRef( false );
+ const isSyncingOutgoingValue = useRef( false );
+
+ useEffect( () => {
+ if (
+ blocks !== previousBlocks.current && (
+ isSyncingIncomingValue.current ||
+ isIgnored
+ )
+ ) {
+ isSyncingIncomingValue.current = false;
+ previousBlocks.current = blocks;
+ previousIsPersistent.current = isPersistent;
+ } else if (
+ blocks !== previousBlocks.current ||
+ // This happens when a previous input is explicitely marked as persistent.
+ ( isPersistent && ! previousIsPersistent.current )
+ ) {
+ // When knowing the blocks value is changing, assign instance
+ // value to skip reset in subsequent `componentDidUpdate`.
+ if ( blocks !== previousBlocks.current ) {
+ isSyncingOutgoingValue.current = true;
}
- if (
- newBlocks !== blocks ||
- // This happens when a previous input is explicitely marked as persistent.
- ( newIsPersistent && ! isPersistent )
- ) {
- // When knowing the blocks value is changing, assign instance
- // value to skip reset in subsequent `componentDidUpdate`.
- if ( newBlocks !== blocks ) {
- this.isSyncingOutcomingValue = true;
- }
+ previousBlocks.current = blocks;
+ previousIsPersistent.current = isPersistent;
- blocks = newBlocks;
- isPersistent = newIsPersistent;
-
- if ( isPersistent ) {
- onChange( blocks );
- } else {
- onInput( blocks );
- }
+ if ( isPersistent ) {
+ onChange( blocks );
+ } else {
+ onInput( blocks );
}
- } );
- }
+ }
+ }, [ blocks, isPersistent ] );
- render() {
- const { children } = this.props;
+ useEffect( () => {
+ if ( isSyncingOutgoingValue.current ) {
+ isSyncingOutgoingValue.current = false;
+ } else {
+ isSyncingIncomingValue.current = true;
+ resetBlocks( value );
+ }
+ }, [ value ] );
- return children;
- }
+ return children;
}
-export default compose( [
- withRegistryProvider,
- withDispatch( ( dispatch ) => {
- const {
- updateSettings,
- resetBlocks,
- } = dispatch( 'core/block-editor' );
-
- return {
- updateSettings,
- resetBlocks,
- };
- } ),
-] )( BlockEditorProvider );
+export default withRegistryProvider( BlockEditorProvider );
diff --git a/packages/block-editor/src/components/provider/with-registry-provider.js b/packages/block-editor/src/components/provider/with-registry-provider.js
index cdb3b7fe7b2de..036bd642b07f0 100644
--- a/packages/block-editor/src/components/provider/with-registry-provider.js
+++ b/packages/block-editor/src/components/provider/with-registry-provider.js
@@ -14,7 +14,7 @@ import applyMiddlewares from '../../store/middlewares';
const withRegistryProvider = createHigherOrderComponent( ( WrappedComponent ) => {
return withRegistry( ( { useSubRegistry = true, registry, ...props } ) => {
if ( ! useSubRegistry ) {
- return ;
+ return ;
}
const [ subRegistry, setSubRegistry ] = useState( null );
@@ -32,7 +32,7 @@ const withRegistryProvider = createHigherOrderComponent( ( WrappedComponent ) =>
return (
-
+
);
} );