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

Editor: PostTextEditor: Fix case where empty state value defers to prop #9513

Merged
merged 2 commits into from Sep 3, 2018

Conversation

aduth
Copy link
Member

@aduth aduth commented Aug 31, 2018

Extracted from #9403

This pull request seeks to fix a bug with PostTextEditor where intended state value is not always reflected in the rendered textarea when empty. Since previously, it relied on a simple truthy condition to determine whether to use state or props value, if the user had erased all content from the textarea, it would effectively trigger this fallback to props value to occur, thus disregarding the local (user-intended) state.

In practice, this had no effect only because props edit state was kept in sync, so the value remained the same. The issue became more obvious through related refactoring in #9403.

Testing instructions:

There should be no regressions in the behavior of the PostTextEditor.

Ensure unit tests pass:

npm run test-unit editor/src/components/post-text-editor/test/index.js

Future tasks:

In testing this myself, I discovered some unfortunate consequences of our "delayed sync" blocks parsing behavior. Since we rely on the blur event to persist content, the sync doesn't always occur, for example when using the keyboard shortcut to switch between modes. I created an issue at #9512 to track (with potential fix included).

@aduth aduth added [Type] Bug An existing feature does not function as intended [Feature] Code Editor Handling the code view of the editing experience labels Aug 31, 2018
if ( state.persistedValue !== props.value && ! state.isDirty ) {
const isReceivingNewNonConflictingPropsValue = (
state.persistedValue !== props.value &&
! state.isDirty
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I reading the condition wrong or this should drop the !?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same condition which existed previously. Is the confusion in the naming? I struggled with it 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, the conflict exists only if the state is dirty?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry NonConflicting :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, the conflict exists only if the state is dirty?

Correct, this is testing for "non-conflicting".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still confused though :)

For me we should always call computeDerivedState unless the state.isDirty = false , am I wrong? Can't we simplify all these condition with just isDirty checks?

// to getDerivedPropsFromState on this state change.
//
// See: getDerivedPropsFromState (hasStoppedEditing)
this.setState( { value: null } );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can replace this with this.setState( { persistedValue: this.state.value, isDirty: false } ); right? It seems a bit clearer to me but not very important though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can replace this with this.setState( { persistedValue: this.state.value, isDirty: false } ); right? It seems a bit clearer to me but not very important though.

I don't think we can, or at least not without making the newly-added hasStoppedEditing effectively dead code (since when would value then ever be null)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was actually thinking hasStoppedEditing is useless because that's the exact purpose of isDirty

value: null,
isDirty: false,
};
this.state = computeDerivedState( props );
}

static getDerivedPropsFromState( props, state ) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized.... there's no such thing as getDerivedPropsFromState. There is a getDerivedStateFromProps. I think this has been dead code all along?

@aduth aduth force-pushed the fix/post-text-editor-local-state branch from 2cf6ae6 to 3b2444e Compare August 31, 2018 18:29
@aduth
Copy link
Member Author

aduth commented Aug 31, 2018

The new approach in 3b2444e is much simpler, and leverages isDirty as the key indicator for whether to derive from props.

* @see stopEditing
*
* @param {Event} event Change event.
*/
edit( event ) {
const value = event.target.value;
this.props.onChange( value );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is a bit weird :). I suppose this is only needed to trigger the post dirtiness, right? I wonder if a specific action is not better.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Granted it's not being changed in this PR

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate on what's weird here? onChange is called to surface the edit to the editor store immediately (so as to mark for dirty detection).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we filling the content in the edits? For me the blocks is the edits of the content property. And we're already filling the blocks properly when persisting. I bet this is only needed to trigger a "dirty" state.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I bet this is only needed to trigger a "dirty" state.

Pretty much this, yes 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this better than a SET_DIRTY action or something like that? It's a bit clearer

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an option, one which would contradict the purpose of proposed #7409.

Copy link
Member Author

@aduth aduth Sep 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't necessarily agree that SET_DIRTY is clearer in the broader sense. In practical terms as it impacts what we're doing here, sure, the intent with calling editPost is to make sure the post becomes marked as dirty, but dirtiness is not really meant to be an explicit action, more a reflection of the current state (diff of edits and saved post). It's by various complexities of content/blocks syncing that we've landed at our current implementation, but I'd rather not further engrain ourselves to this idea of "make dirty" if we can help it.

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

@noisysocks noisysocks merged commit 71c4d8f into master Sep 3, 2018
@noisysocks noisysocks deleted the fix/post-text-editor-local-state branch September 3, 2018 09:08
@mtias mtias added this to the 3.8 milestone Sep 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Code Editor Handling the code view of the editing experience [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants