-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Text Editor: Fix inserting blocks #1077
Conversation
editor/selectors.js
Outdated
@@ -3,6 +3,7 @@ | |||
*/ | |||
import moment from 'moment'; | |||
import { first, last, get } from 'lodash'; | |||
import { createSelector } from 'reselect'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recently published a Calypso-like memoization library: https://github.com/aduth/rememo
Curious if you have thoughts on whether reselect
is a better approach or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, I don't have any preference. The advantage of reselect
is that it's kind of the default with Redux, more developers already know how to use it. But at the same time, rememo
is probably easier to learn.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point. I've always found the examples they chose in their documentation to be overly daunting for the sake of showcasing a complex example, but what you've shown here is much simpler.
Another worry is that they don't really prescribe easy patterns for accepting arguments to a selector:
https://github.com/reactjs/reselect#q-how-do-i-create-a-selector-that-takes-an-argument
Here worked out easy enough because getBlocks
doesn't accept any anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mmm! Good point about the selectors with arguments, I think we'll need this quickly. Though according to their docs, we could write this
const createSelectorWithArguments = ( extractors, resolver ) => {
const memoizedResolver = memoize( resolver );
const memoizedSelector = createSelector( extractors, memoizedResolver );
return ( state, ...args ) => {
const selector = memoizedSelector( state );
return selector( ...args );
};
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mmm looks like https://github.com/toomuchdesign/re-reselect do exactly what I've proposed.
But I think I'll just switch to rememo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually! forget my implementation it's completely broken I think :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aduth I think there's a problem somewhere in rememo
. I've replaced the selector by this:
export const getBlocks = createSelector(
( state ) => {
return state.editor.blockOrder.map( ( uid ) => (
state.editor.blocksByUid[ uid ]
) );
},
state => state.editor.blockOrder,
state => state.editor.blocksByUid,
);
and I'm getting a new Instance even if the state didn't change.
I'll probably keep reselect for now, and feel free to update once fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@youknowriad That's incorrect usage. There should be two arguments at most, so the second should be changed to:
( state ) => [
state.editor.blockOrder,
state.editor.blocksByUid,
]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still not working 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated with the last version of rememo
it works great.
Unrelated to the conversation above, this seems to be working well! Thanks for tackling this so fast. |
editor/modes/text-editor/index.js
Outdated
} | ||
|
||
onBlur() { | ||
const blocks = parse( this.state.value ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As noted in chat, can we test here whether the value has changed from what we know to have been the previous value before parsing and assigning new blocks?
Total aside but on the note of memoized selectors: I've been quite intrigued by Vue's approach for change tracking using |
Steps to reproduce:
Expected: Serialized block content appended to the end of content Guessing our visual editor mode insertion point is interfering. |
3a67d8c
to
44f6fe1
Compare
Good catch @aduth. I've addressed the issue by simplifying the insertion point behaviour and moving the logic to a testable selector in 44f6fe1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the refactor. This works well now 👍
closes #1072
This bug is way harder to solve than it seems because for performance reasons, we want to avoid calling parse/serialize as much as we can.
The solution here involves:
getBlocks
selector returns the same array instance if the state didn't change