-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
renderElement does not support React Hooks #43201
Comments
@bigaru What's the reason for implementing a React hook in a In terms of the |
Hi @talldan I see your point with block validation. However, not all hooks make your code impure. The counter-examples are const ThemeContext = createContext('#000')
const DeeplyNestedElement = () => {
const themeColor = useContext(ThemeContext)
return <div style={{ background: themeColor }}>Foo Bar</div>
}
const Root = () => (
<ThemeContext.Provider value="#000">
<DeeplyNestedElement />
</ThemeContext.Provider>
) Currently the behavior between ClassComponent and FunctionalComponent is inconsistent: // works fine in save
class FooComponent extends React.Component {
constructor(props) {
super(props)
this.value = 'FooBar'
}
componentDidMount() {
this.setState({ value: 'NewFoo' })
}
render() {
return <div {...this.props}>{this.value}</div>
}
}
// fails in save
const FooComponent = (props) => {
const [value, setValue] = useState('FooBar')
useEffect(() => setValue('NewFoo'))
return <div {...props}>{value}</div>
} Even if the developer writes pure code. There are a lot of react libraries which use hooks underneath. For example, the code below is pure (at least from developer POV). Since the pie-chart library uses hooks, it will fail in save function. import { PieChart } from 'react-minimal-pie-chart'
const Chart = ({ attributes }) => {
const { value1, value2, } = attributes
return (
<PieChart
data={[
{ title: 'Uno', value: value1, color: '#E38627' },
{ title: 'Dos', value: value2, color: '#C13C37' },
]}
/>
)
} Overall, it still seems to me that this behavior is not intentional. Furthermore I found a related issue #15873 . |
If the goal of I can see how There is possibly a future situation where it may need to work differently, which is to support block hydration (#38224).
It looks like the same discussion on that issue as here though. This can definitely be considered a bug in |
Worth mentioning that even then that can cause issues - a unique id might be in a reusable block, and that reusable block could be inserted twice, and then there would be duplicate ids. The only safe option is a dynamic block. |
My main motivation is that I can use the same react component inside the save function and block hydration. 😄 It is good to see that there is ongoing progress for a better approach of block hydration:
I understand your reasoning
So it's up to you, whether you like to keep this issue open as a reminder. |
Interesting. Good to hear you're exploring this. Have you found workaround for the If there were a fix, I do also wonder it could be worth thinking about ways to warn developers of normal static blocks about the pitfalls of using hooks or other kinds of impurity. Maybe block validation warnings are already enough, but the trouble is that a validation issue may not happen until much later. |
I don't want to clutter my code with if-else. Probably the simplest solution is, to render an empty
Maybe we could create a custom eslint plugin for that. |
Our current idea is to replace the real React hooks with our own pure implementation. For example, const noop = () => {};
// Export of useState in `@wordpress/element` for the `save.js` entry points
export const useState = (defaultValue) => [defaultValue, noop]; That way, we don't have to fix the serializer, and the same export different code in different contexts mechanism could be used for other purposes: But we are also open to other ideas 🙂 |
I looked at the code and it seems very interesting. I like your solution, it will definitely fix my problem 😁 However, when I'm thinking about long term maintenance, I have concerns: That is why I'm wondering, is it possible to use the plain react render method underneath and make those customizations on top of it? So when the next react version is released, the serializer will support all new features out of the box. |
Yes, that's another option @gziolo and I briefly explored a while ago. If you want to give it a try, please do! 🙂 These are the primary unit tests that should pass: https://github.com/WordPress/gutenberg/blob/trunk/packages/element/src/test/serialize.js |
I like the idea of pure hooks, particularly of the ones we know can be mimick'd without true react. Has anyone moved forward on this? If not - I might see about giving it a shot (if I can find the time) - would the intent be to replace the already exposed hooks, or maybe make it something like I actually came across this in making some components specifically for allowing me to use the same React component both for editor and save - my blocks are all isolated with a prop - Originally I had a context used like I ended up just having a top-level object hold the state and removed the context, making just set that object's save property to true/false depending. It works, but it's dirty. I also have to pass blockProps in from edit.js/save.js, given that useBlockProps() also causes this error and conditional hooks are "bad". I mean, they are bad but in quotes because I don't think in the context of Gutenberg they'd actually cause any issues. I easily could just keep my components wrapped in a |
Description
It seems that the function
renderElement
frompackages/element/serialize.js
is not able to process React Hooks. As soon as a React hook is used inside save function, the errorInvalid hook call.
is thrown.I double-checked this error against React's probable causes:
However, everything was fine. After using the debugger, I came to the conlusion that the function
renderElement
does not support the React hooks.Furthermore, on the top of the
serialize.js
file is mentioned that the some parts are based on fast-react-render (Btw which is outdated and they even recommend to use vanilla React). That is why I strongly suspect that the serializer is not able to handle React hooks.Step-by-step reproduction instructions
npx @wordpress/create-block example
npx wp-env start && npm start
example
and save the postScreenshots, screen recording, code snippet
No response
Environment info
@wordpress/scripts
23.7.0@wordpress/element
4.13.0@wordpress/env
4.9.0Please confirm that you have searched existing issues in the repo.
Yes
Please confirm that you have tested with all plugins deactivated except Gutenberg.
Yes
The text was updated successfully, but these errors were encountered: