Ckeditor5: Redux App - CKEditor 5 inline "React" plugin - can't use connect() function

Created on 12 May 2019  路  11Comments  路  Source: ckeditor/ckeditor5

Hello,

We are using the CKEditor5 React component, and have successfully set up a classic editor build in our application. Our application is a Redux application.

We are attempting to customize the editor with an inline plugin. Our inline plugin will act as a button that users can click to communicate with another component, that will allow them to pull in blocks of content that have been pre-curated.

We have followed the example outlined here: https://github.com/ckeditor/ckeditor5/pull/1706/commits/0cdd897bec49009be76ebefa13102133523bd87d (Thank you @oleq!) and have been able to create a simple React component for our button. (I think this commit is itself based on the documentation for creating an inline plugin from the CKEditor5 docs.) We can render it just fine inside of our editor. Our issue is that if we attempt to use the redux connect() function to make the component "smart" - that is, allow it communicate with our redux store, the application throws the following error:

Invariant Violation

Could not find "store" in the context of "Connect(MyComponent)". Either wrap the root 
component in a <Provider>, or pass a custom React context provider to <Provider> and the
corresponding React context consumer to Connect(Todo) in connect options.

We suspect this may have to do with the way the plugin is being initialized within CKEditor, but can't be sure. Our entire application is wrapped in a <Provider> which should, in theory, make the Redux store available to any nested components.

Any thoughts on what we can do differently?

question

All 11 comments

Hi! Could you provide some working sample with a minimal amount of code needed to reproduce your issue, so it will be easier for us to analyse the problem?

@Mgsy Happy to do this - we are building CKEditor from the source, so I am trying to find a way to provide an example by way of Code Sandbox that allows for a custom webpack configuration - I don't think this is supported. Any suggestions?

Can you create a repository on GitHub with a project?

OK. I'll need a little bit to get this set up. Once I do I'll post a link.

@Mgsy - here you go, I was able to reproduce the error here:

https://github.com/mattkoch614/ckeditor-redux-plugin

Thanks, @mattkoch614.

@pomek, can you investigate it?

No error occurs after applying the following changes:

src/ckeditor/plugins/CustomButtonEditing.js

@ CustomButtonEditing.js:7 @ 
import Plugin from "@ckeditor/ckeditor5-core/src/plugin";
import { toWidget } from "@ckeditor/ckeditor5-widget/src/utils";
import Widget from "@ckeditor/ckeditor5-widget/src/widget";
import CustomButtonComponent from "./CustomButtonComponent";
+import { Provider } from 'react-redux';
+import { store } from '../../store';
@ CustomButtonEditing.js:91 @ 
export default class CustomButtonEditing extends Plugin {
        function(domDocument) {
          const domElement = this.toDomElement(domDocument);

-          ReactDOM.render(<CustomButtonComponent name={name} />, domElement);
+          ReactDOM.render(<Provider store={ store }><CustomButtonComponent name={name} /></Provider>, domElement);

          return domElement;
        }

Screenshot:

image

Hi @pomek - Thank you for investigating. While this would technically function, the Redux docs discourage directly importing the store like this. This was something we tried initially, but instead of using Provider we just passed it to the component directly using a prop.

They instead recommend that the root level component be wrapped in <Provider store={store}>, which is what the repo does, and let React Redux worry about passing the store down:

https://redux.js.org/faq/store-setup#can-or-should-i-create-multiple-stores-can-i-import-my-store-directly-and-use-it-in-components-myself

Doing it the way you are prescribing here would result in two separate Provider components at different points in the component tree.

I don't know too much about Redux itself but I found an old issue on GH where a user wrapped two different components with the <Provider /> component and he used the same [store] which (for me) means that all those components are using the single store.

https://github.com/reduxjs/react-redux/issues/355#issuecomment-210263808

From the docs above I understood: you need to wrap the main component (<App />) with <Provider /* ... */>. Then, you don't need to wrap any other component with <Provider /> as long as you don't render it manually. If you want to use ReactDOM.render() in your code, you should wrap it once again.

_I can be completely wrong and if I am introducing mess, let me know._

@pomek That's some good sleuthing on your part. I may have been too rigid in adherence to doctrine when it came to the Redux docs. Even though that issue is old, it sort of throws out the idea that having multiple Provider wrappers introduces problems.

I'll give this a shot and see if there are any edge cases that bubble up...

OK, so after some testing, this does work, with a caveat. We have some tests that are utilizing a mock store at the top most component level, and using this method of two Provider tags doesn't allow for it to be passed down to the CustomButtonComponent component directly.

Overall, I think we can call this specific issue solved, but I will have to find a way to get a mock store injected into multiple components at build time if this is going to be the approach.

If you have any closing thoughts I am all ears.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pomek picture pomek  路  3Comments

jodator picture jodator  路  3Comments

metalelf0 picture metalelf0  路  3Comments

oleq picture oleq  路  3Comments

benjismith picture benjismith  路  3Comments