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

useBlockSync(): Reset inner blocks when component unmounts #51783

Merged
merged 1 commit into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe( 'useBlockSync hook', () => {
jest.clearAllMocks();
} );

it( 'resets the block-editor blocks when the controll value changes', async () => {
it( 'resets the block-editor blocks when the controlled value changes', async () => {
const fakeBlocks = [];
const resetBlocks = jest.spyOn( blockEditorActions, 'resetBlocks' );
const replaceInnerBlocks = jest.spyOn(
Expand All @@ -58,7 +58,7 @@ describe( 'useBlockSync hook', () => {
const onChange = jest.fn();
const onInput = jest.fn();

const { rerender } = render(
const { rerender, unmount } = render(
<TestWrapper
value={ fakeBlocks }
onChange={ onChange }
Expand Down Expand Up @@ -88,9 +88,16 @@ describe( 'useBlockSync hook', () => {
expect( onInput ).not.toHaveBeenCalled();
expect( replaceInnerBlocks ).not.toHaveBeenCalled();
expect( resetBlocks ).toHaveBeenCalledWith( testBlocks );

unmount();

expect( onChange ).not.toHaveBeenCalled();
expect( onInput ).not.toHaveBeenCalled();
expect( replaceInnerBlocks ).not.toHaveBeenCalled();
expect( resetBlocks ).toHaveBeenCalledWith( [] );
} );

it( 'replaces the inner blocks of a block when the control value changes if a clientId is passed', async () => {
it( 'replaces the inner blocks of a block when the controlled value changes if a clientId is passed', async () => {
const fakeBlocks = [];
const replaceInnerBlocks = jest.spyOn(
blockEditorActions,
Expand All @@ -100,7 +107,7 @@ describe( 'useBlockSync hook', () => {
const onChange = jest.fn();
const onInput = jest.fn();

const { rerender } = render(
const { rerender, unmount } = render(
<TestWrapper
clientId="test"
value={ fakeBlocks }
Expand Down Expand Up @@ -138,8 +145,16 @@ describe( 'useBlockSync hook', () => {
expect( onChange ).not.toHaveBeenCalled();
expect( onInput ).not.toHaveBeenCalled();
expect( resetBlocks ).not.toHaveBeenCalled();
// We can't check the args because the blocks are cloned.
expect( replaceInnerBlocks ).toHaveBeenCalled();
expect( replaceInnerBlocks ).toHaveBeenCalledWith( 'test', [
expect.objectContaining( { name: 'test/test-block' } ),
] );

unmount();

expect( onChange ).not.toHaveBeenCalled();
expect( onInput ).not.toHaveBeenCalled();
expect( resetBlocks ).not.toHaveBeenCalled();
expect( replaceInnerBlocks ).toHaveBeenCalledWith( 'test', [] );
} );

it( 'does not add the controlled blocks to the block-editor store if the store already contains them', async () => {
Expand Down
19 changes: 19 additions & 0 deletions packages/block-editor/src/components/provider/use-block-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,19 @@ export default function useBlockSync( {
}
};

// Clean up the changes made by setControlledBlocks() when the component
// containing useBlockSync() unmounts.
const unsetControlledBlocks = () => {
__unstableMarkNextChangeAsNotPersistent();
if ( clientId ) {
setHasControlledInnerBlocks( clientId, false );
__unstableMarkNextChangeAsNotPersistent();
replaceInnerBlocks( clientId, [] );
} else {
resetBlocks( [] );
}
};

// Add a subscription to the block-editor registry to detect when changes
// have been made. This lets us inform the data source of changes. This
// is an effect so that the subscriber can run synchronously without
Expand Down Expand Up @@ -287,4 +300,10 @@ export default function useBlockSync( {
unsubscribe();
};
}, [ registry, clientId ] );

useEffect( () => {
return () => {
unsetControlledBlocks();
};
}, [] );
}