ianstormtaylor / slate

A completely customizable framework for building rich text editors. (Currently in beta.)
http://slatejs.org
MIT License
29.89k stars 3.25k forks source link

Input after ReactEditor.focus doesn't work #3634

Open harrisonturton opened 4 years ago

harrisonturton commented 4 years ago

What's the current behavior?

Bug Report

Sandbox reproducing the issue

The first button directs the focus fine, and I can immediately begin typing. When I click the second button, however, my typing is not caught by the input until I click it again.

The createEditor() state in this example is being held by useState inside an object. I debated removing this to make it more "minimal", but I think that might be relevant – react perhaps does some weird things behind the scenes with hooks that might be interfering.

What's the expected behavior?

I expect to be able to begin typing and have my keypresses caught by the input immediately after ReactEditor.focus is called, and this should work regardless of how many createEditor() instances exist on the page.

Slate Version

"slate": "^0.57.1",                                                                                                                                                          
"slate-history": "^0.57.1",                                                                                                                                                  
"slate-react": "^0.57.1"                                                                                                                                                     

OS & Browsers I could reproduce the issue on

cameracker commented 4 years ago

I wasn't able to look at this in depth, but I think this might be caused by the onBlur event for the first editor firing after the onFocus event of the second editor, and this is causing the focus to be removed from the second editor shortly after it's granted when the button is clicked

harrisonturton commented 4 years ago

I thought it might've been because I was storing the editor state inside useState instead of useMemo, but I tried both and got the same behaviour. I even tried useReducer, didn't work either.

cameracker commented 4 years ago

Hey @harrisonturton , I know it's been a month but I took a look at this and produced a fork of the original code sandbox.

https://codesandbox.io/s/slate-05x-69xnt

What I've noticed is that this for some reason only seems to happen when clicking Focus One then Focus Two. Any other combination, even after creating new "pages" seems to work correctly, at least for me. This leads me to think there's something up with how the second editor is being initialized but I don't see anything wrong with it at a glance.

sebastianseilund commented 4 years ago

I described a workaround in https://github.com/ianstormtaylor/slate/issues/3696#issuecomment-723497830

TL;DR; Workaround: Make sure that your onChange handler does not cause a re-render if the Slate value has not changed.

I mad a working Sandbox fork based on @CameronAckermanSEL's non-working example. Make onChangePage not change the pages state object if the content didn't actually change.

  const onChangePage = (id: number) => (content: Node[]) =>
    setPages((pages) => {
      if (pages[id].content === content) {
        return pages;
      }
      return {
        ...pages,
        [id]: {
          ...pages[id],
          content: content
        }
      };
    });