-
Notifications
You must be signed in to change notification settings - Fork 3.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
Passing custom props to nodes #763
Comments
Solution 2. and 3. boil down to passing props to the nodes. When one of these prop change, every node will have to re-render, since Slate cannot know what they are used for. I always thought Slate would re-render everything on schema change. Solution 1. would break people's code. I would not try to compare schemas but using referential equality, it seems bug-prone. |
I'm not sure if this is a solid way to handle that, but it works well for me right now.
|
@bunterWolf Yes it works for the first rendering. But if your prop |
I've started a PR: #764 |
Hey @SamyPesse interesting use case! What is the exact use case? What's props do the nodes need from the editor? Curious to get my mind around it. I've got a few ideas for solutions but not sure I know the exact problem enough to know which one feels right. |
@ianstormtaylor I've started describing the use-case in the PR (#764 (comment)), but here are more details: We want to highlight (and change the UX) of some nodes according to the browser's url. Basically the user can click on a comment icon on the right, it changes the url to We are using We first thought about using react-router's This is because context updates do not trigger re-render (facebook/react#2517 (comment)), basically a React's context should be constant or provide its own subscribing model. We also have other use cases for this, where our node components need to know about props from the editor's parent. |
@SamyPesse Okay, damn, that is hard haha. What about if we allowed plugins to listen to the lifecycle events of the editor, such that you could do something like this inside a plugin: function plugin() {
const store = new Store()
function editorDidMount(editor, props) {
store.set(props.pathname)
}
function editorDidUpdate(editor, props) {
store.set(props.pathname)
}
class Comment extends React.Component {
state = {
pathname = store.get(),
}
componentDidMount = () => {
store.on(this.onPathnameChange)
}
componentWillUnmount = () => {
store.off(this.onPathnameChange)
}
onPathnameChange = (pathname) => {
this.setState({ pathname })
}
render = () => {
const { pathname } = this.state
const { node } = this.props
const id = node.data.get('id')
const active = pathname == id
return ...
}
}
const schema = {
marks: {
comment: Comment,
}
}
return {
editorDidMount,
editorDidUpdate,
schema,
}
} I think that would allow you to get a lot fewer updates, since you'd be able to only update when the props above changed, or better yet only when their impacts below changed. But it's just a quick idea, could be some gaping holes. Not the most amazing, since you're back to monitoring a store with handlers in a not very React way. But not sure there's a better way unless React supported this natively with |
@ianstormtaylor +1 to the idea of plugin listening to lifecycle events. This idea of yours also seems to touch upon the conversation in #715 as well. I'd also like to throw in another related usecase that I had mentioned in #764 to @SamyPesse - communicating from the editor to specific nodes. I feel like all three requests ('global context', 'props from editor to plugin', and the one I just mentioned above) seem to be getting around limitations in current patterns of passing information via the editor and the discussion might help from keeping all of them in mind. |
@oyeanuj thanks, I agree with you, keeping those all in mind at once sounds good. I think for the spellchecking case of #764, you might actually be able to handle that in the node itself? Instead of needing to pass them down from the editor? @SamyPesse Actually, Edit:
Nevermind about |
@ianstormtaylor I was considering handling it in the node for fetching URL metadata, and possibly even for mentions (For spell/grammar check, I was going to send the whole document for some other analysis as well, so just the node wouldn't work). But the only downside to that method is that the rendering components can't be 'dumb/presentational' anymore and need to be connected to outside. A plugin user can't just supply a component to handle the rendering. An alternative would be something similar to @SamyPesse' original comment or @bunterWolf's suggestion above which circles back to this ticket 😄 |
I'm in the same boat. If it helps, my use case is a question editor that has void nodes that show the default answers of user-facing inputs inline (e.g. choice, text). They (the default answers) are stored in an object elsewhere and passed in as a prop to slate. |
Finally this is not required, and it should not be done by slate. The solution is to use a store like @ianstormtaylor suggested but in the parent component in your apps (create the store, create a schema from this store, update the store when the props of your component changes). It works very well in my application. Closing this issue. |
Awesome, thanks @SamyPesse! |
@ianstormtaylor I'd still vote a first-class pattern or API to address the all these related cases, like we discussed above. Since this ticket is closed, should we address those discussions in their related tickets or open an umbrella ticket which deals with these cases (#709, #715, and this one)? @SamyPesse In your solution, by 'parent component', are you referring to the editor or its parent or something else? |
Samy meant the parent of the editor. I'm still down for the one that adds a data property to the state model itself. And then that could easily be used as the store in a way to keep the data in a serialization location. I think I might be down to still have the lifecycle methods as plugin methods. Although I'd like to experiment with making plugins HOCs to achieve it first instead. |
@ianstormtaylor Thanks for the clarification. So, in this method, all the nodes would get re-rendered.. wondering if you have ideas of how best to address where one only wants to communicate to specific nodes from the editor level (without needing every other node to re-render) in my usecase? |
@oyeanuj I think for that case you'd want to setup your own store/subscribing pattern like I assume what Samy's done, and use that to then call I'm just not sure Slate should standardize it yet, unless we come across a lot of use cases that are always the exact same. It feels like the subscription handling stuff could get very complex. |
@ianstormtaylor Fair enough! |
In our application, some of our node components requires some props from the parent.
The solution we tried was to create a schema depending on these props:
But Slate doesn't re-render when the
schema
changed.So I'm proposing 3 solutions:
shouldComponentUpdate
to re-render when theschema
changedprevProps.schema
withprops.schema
? If the schema is inlined in therender()
method, and so unique to eachrender
callEditor
to the nodesprops
toEditor
:<Editor props={{ customPropToPassToNode: 'test' }} ... />
@ianstormtaylor @Soreine what do you guys think ?
The text was updated successfully, but these errors were encountered: