You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It's pretty common to have a React component that needs access to some part of the EditorState in the render function (e.g. a formatting button that checks the current selection's marks to determine whether it should be activated). Sometimes, React node view components also need to access parts of the EditorState outside of their own node.
At the moment, the way to do this is with useEditorState, which triggers a re-render for the consuming component on every single update to the document.
It's possible that we can't do much better than this, but now that we have very good render memoization in the beta release, it would be nice to provide a way for components to access parts of the EditorState (say, a plugin state) without needing to rerender on every update.
One way to accomplish this could be to have a new hook, useSelectEditorState, that takes a selector function as an argument. I'm working through this in my head as I write it, so forgive me if this doesn't pan out, but I'm imagining something like:
functionuseSelectEditorState<Value>(selector: (state: EditorState)=>Value){constview=useContext(EditorViewContext)// We access the view directly to// avoid a first render with an// undefined valueconst[selected,setSelected]=useState(()=>selector(view.state))// can’t actually use `useEditorEffect` here,// need a way to register something// that runs on every state updateuseEditorEffect((view)=>{setSelected(view.state)},[selector])returnselected}
I think this literal code doesn’t work. As noted in the comment, we need a new effect registration hook (internal) to register an effect that runs on every state update. Also, I think as written this could introduce state tearing, because the selected value is updated in a layout effect, so during the render after a state update, the actual editorstate will be “ahead” of the selected value.
Again, it’s possible that there isn’t a clean way to do this (some part of me keeps saying “use useSyncExternalStore!" But I have no idea if that’s right) without state tearing, in which case we shouldn’t do it. But I keep thinking about it so I figured I should share!
The text was updated successfully, but these errors were encountered:
I think even with useSyncExternalStore there are some state issues that come up. React Redux tries to detect these issues, I think, and re-render automatically. They discuss it in their warnings about their hooks API.
I also wonder if we're drawn to a Redux-like API for familiarity reasons, when other folks might not immediately reach for something like useSelector. We could wait and see what solutions folks come up with if they run into performance issues.
Yeah I think there's no urgency on this, I just wanted to get it down/out of my head. I haven't run into an actual performance issue caused by this yet, but I keep thinking about it because I had to be very deliberate in order to avoid it in the StrictMode work! I agree that it makes sense to accumulate some cases where this is actually an issue and get feedback on what folks would want here
smoores-dev
changed the title
Add a selector to useEditorState
Add support for subscribing to changes on subsets of the EditorState
Dec 18, 2024
It's pretty common to have a React component that needs access to some part of the EditorState in the render function (e.g. a formatting button that checks the current selection's marks to determine whether it should be activated). Sometimes, React node view components also need to access parts of the EditorState outside of their own node.
At the moment, the way to do this is with
useEditorState
, which triggers a re-render for the consuming component on every single update to the document.It's possible that we can't do much better than this, but now that we have very good render memoization in the beta release, it would be nice to provide a way for components to access parts of the EditorState (say, a plugin state) without needing to rerender on every update.
One way to accomplish this could be to have a new hook,
useSelectEditorState
, that takes a selector function as an argument. I'm working through this in my head as I write it, so forgive me if this doesn't pan out, but I'm imagining something like:I think this literal code doesn’t work. As noted in the comment, we need a new effect registration hook (internal) to register an effect that runs on every state update. Also, I think as written this could introduce state tearing, because the selected value is updated in a layout effect, so during the render after a state update, the actual editorstate will be “ahead” of the selected value.
Again, it’s possible that there isn’t a clean way to do this (some part of me keeps saying “use useSyncExternalStore!" But I have no idea if that’s right) without state tearing, in which case we shouldn’t do it. But I keep thinking about it so I figured I should share!
The text was updated successfully, but these errors were encountered: