-
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
wp-each "Cannot access 'state' before initialization" #69266
Comments
I've been trying to figure out long before posting this issue why my code stopped working, and of course just after posting it I found a (temporary) solution. Simply get the state reference before creating your actual state implementation:
But this shouldn't be needed right? |
I'm unable to reproduce with 6.18.0 (current version shipped in 20.3) or 6.17.0 (version shipped in 20.2). Could you please modify this Stackblitz template until you reproduce the problem? If you don't want to use StackBlitz, then please create a new block and try to reproduce it there. |
Ok, after a lot of testing I figured out what the issue is I'm experiencing. Please take the time to read this while I try to explain, hopefully it will create a clear picture of what I'm trying to achieve and where it is going wrong. I really like how quickly you can share store data between blocks on the front-end and have blocks respond to state changes made by other blocks. I've made some "complex" systems with it, where on the back-end the interactivity state also changes and the navigation router updates the blocks perfectly without needing a page reload. love it! A lot of my blocks use state derived getters that are influenced by the interactivity context they have. This is really useful in the wp-each directive, where context data needs to be combined with other state data. This way different blocks can use the same interactivity state derived getters, making for very efficient code. Instead of duplicating the code of these getters for every block view script, I gathered the shared getters into a separate script that is loaded as a dependency for these view scripts. And this is where things go wrong. When the script module with the shared state is loaded without being enqueued (by wp_script_modules), the script is added to be preloaded in the header as and added to the importmap. I'm able to confirm that the script is loaded correctly and is used by the different blocks view script. BUT, it works sometimes, which I think indicates there is a loading order problem. I even exported and imported the interactivity state from the shared script module into the block view scripts, hoping the browser would understand the dependencies between all the module scripts and load them in the correct order. So just enqueue the script module when it is needed? This also didn't work. When a script module is enqueued, it is added to the header similar to block view script modules as <script type="module" src="link_to_script"></script>. But the error in this git issue still occurs. While the actual getter on the shared state was called by wp-directives, using the state in these getters for state derived data caused an error to be thrown. I did finally find a fix (but I don't think it's a solution), if the shared script module is registered before all the blocks view script modules (enqueue order doesn't matter), the shared module script is place before the blocks view <script type="module"... tags in the header. This resolves this git issue and the random loading crash of the Interactivity API on the front-end on page load for me. This means for now if you want to share an Interactivity state with reusable methods between blocks, you will have to register the script module before the blocks are registered in Gutenberg and enqueue it, instead of working with dependencies. You could also create a "context" block container with the shared interactivity state in its view script module, that houses the blocks that use this shared interactivity state. I haven't tested this, but this way the shared script module should always be loaded first. But this also raises some questions:
I might not be understanding everything about how modules work in the browser, but it would be nice if there is an official way of sharing code between interactivity states to prevent redundant code in my projects. |
Description
I've updated gutenberg from a v18... to the current v20.2.0 and it seems something has changed with how the state is initialised before directives are parsed.
My wp-each directive referencing a state derived getter wasn't a problem before. Now when the wp-each directive is parsed and calls a getter on the state that uses the state variable I'm getting the error: "ReferenceError: Cannot access 'state' before initialization"
I had to wrap the first access to the state in the getter with a try catch to find out this was the problem.
Step-by-step reproduction instructions
Screenshots, screen recording, code snippet
Example:
view.js state getter snippet
render.php snippet
Environment info
Wordpress 6.7.2
Gutenberg 20.2.0
Custom theme
Please confirm that you have searched existing issues in the repo.
Please confirm that you have tested with all plugins deactivated except Gutenberg.
Please confirm which theme type you used for testing.
The text was updated successfully, but these errors were encountered: