From 61394590e9b977f0bbf3b6f92df9cbb25a5457d4 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 28 Jun 2019 17:00:12 -0400 Subject: [PATCH] Block Editor: Reimplement BlockEditorProvider using hooks --- .../src/components/provider/index.js | 179 +++++++----------- .../provider/with-registry-provider.js | 4 +- 2 files changed, 66 insertions(+), 117 deletions(-) diff --git a/packages/block-editor/src/components/provider/index.js b/packages/block-editor/src/components/provider/index.js index 6d06246ca9170a..fe1dc7630b2aef 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 cdb3b7fe7b2ded..036bd642b07f0b 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 ( - + ); } );