1

I am trying to use Draft.js in the Blog app I am creating. It all seems fine when saving data to the database and getting it back, just I cannot seem to get createWithContent to work.

When I write the following, the data does get saved to the database as I am simply creating an empty editor which then is updated by the user and sent to the database after convertToRaw.

const postDetails = useSelector((state) => state.postDetails);
const { loading, post, error } = postDetails; 
const editorContent = EditorState.createEmpty();

const [editorState, setEditorState] = useState({ editorState: editorContent });

const handleEditorChange = (editorState) => { setEditorState({ editorState }) }

const submitHandler = (e) => {
    e.preventDefault();
    dispatch(
      updatePost({
        _id: id,
        title,
        image,
        images,
        paragraph: JSON.stringify(
          convertToRaw(editorState.editorState.getCurrentContent())
        ),
      })
    );
  };

<Editor
   editorState={editorState.editorState}
   onEditorStateChange={handleEditorChange}
 />

But when I use

EditorState.createWithContent(convertFromRaw(JSON.parse(post.paragraph)))

which is what I really want (the paragraph to be filled out with the post.paragrah coming from the database), I get the following error:

enter image description here

A cross-origin error was thrown. React doesn't have access to the actual error object in development.

I am taking care of cross-origin this way:

app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', '*'); 
  res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content, Accept, Content-Type, Authorization'); 
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS'); 
  next();
});

Also, when i console.log(post.paragraph) i do get my paragraph: enter image description here

but what i noticed is that i also get 2 undefined before receiving my paragraph and this could be part of the issue.

To fix this i have tried both this:

const editorContent =   post ?
    EditorState.createWithContent(convertFromRaw(JSON.parse(post.paragraph))) : 
    EditorState.createEmpty();
    
    const [editorState, setEditorState] = useState({ editorState: editorContent });

and this:

const editorContent = await post.paragraph;
          if (post.paragraph) {
            res.send({ editorContent: EditorState.createWithContent(convertFromRaw(JSON.parse(post.paragraph))) });
          } else {
              res.send({ editorContent: EditorState.createEmpty()});
            }
            return editorContent;
          })
    
    
        const [editorState, setEditorState] = useState({ editorState: content });

I have done lots of research on the web but I didn't manage to come up with anything successfull. Hope you guys can help. Thanks in advance

Francesco
  • 549
  • 1
  • 8
  • 14
  • there should be a warning or error in the console or network tabs in devtools, please check them out and add that information to your question – diedu Nov 15 '20 at 22:58
  • Hi diedu, thanks for helping out. I did add the error in my question: A cross-origin error was thrown. React doesn't have access to the actual error object in development. Is that not enough? Thanks – Francesco Nov 16 '20 at 08:54
  • 1
    it seems the main error is happening when parsing the JSON, log the json string you're trying to parse to see if it's valid – diedu Nov 16 '20 at 14:23
  • Thanks alot for trying to help out. post.paragraph does exist as you can see from the console.log above, though one thing i hadn't noticed before is that i get 2 Undefined before DevTool is able to log post.paragraph which i think could be the cause of the problem. Why do you think this is happening? – Francesco Nov 16 '20 at 17:00
  • 1
    if that's the case just wrap that part of the code in an if `if (post.paragraph) EditorState.createWithContent(...` since you didn't specify where and how you're fetching the post data I guess there is some async operation happening – diedu Nov 16 '20 at 17:53
  • Thanks diedu, you can see the full code here https://stackoverflow.com/questions/64808416/draft-js-createwithcontent-or-convertfromraw-throwing-error (i am working with Redux store). Anyways, i tried as you suggested: `const content = (async (err, res) => { const editorContent = await post.paragraph; if (post.paragraph) {res.send({ editorContent: EditorState.createWithContent(convertFromRaw(JSON.parse(post.paragraph))) });` – Francesco Nov 17 '20 at 08:59
  • `} else {res.send({ editorContent: EditorState.createEmpty()});};return editorContent;}); const [editorState, setEditorState] = useState({ editorState: content }); ` but i think i am doing something wrong because i get the following error: EditorState.getImmutable is not a function. What do you reckon? Thanks alot again for helping out – Francesco Nov 18 '20 at 06:25
  • Hi diedu, as you can see i have tried a few things without success. See updated post. Any suggestion would be very much appreciated. Thanks – Francesco Nov 18 '20 at 20:16
  • I'm having the exact same problems with cors and getting `undefined` before receiving `blocks` and I can't retrieve the formatted `text`. Have you managed to solve this? @Francesco – SK1dev Nov 22 '20 at 09:02
  • 1
    Nope, unfortunately. Hopefully a good soul will come to help. I am using markdown for the time being as a temporary alternative. If you find a way to tackle the problem please let me know. Thanks – Francesco Nov 22 '20 at 21:54
  • @Francesco Thanks for your reply. I will do, definitely! I may go with that approach temporarily too if I can't find a solution. – SK1dev Nov 23 '20 at 09:47

1 Answers1

0

The main problem is when you trying to parse the JSON content,

JSON.parse(post.paragraph)

the content is undefined. That's why you're getting the error. You shouldn't render the content until the data is loaded. In my particular problem was the following:

const BlogPostPage: React.FC<MatchProps> = (props: MatchProps) => {

const classes = useStyles();

const { data, loading, error } = useGetBlogQuery({
    variables: {
        id: props.match.params.id
    }
});


return (
    <BlogPostContent markdown={data?.blog?.contentJson}></BlogPostContent>
);
}

In this piece of code, I am calling an async query through the apollo client. However, on the rendering call, I was getting the same error as yours. Then, I have added the following code, to wait until data is loaded. After data is loaded, the hook is triggered and re-rendered the component.

    if (loading) return (<>{"loading..."}</>);
Yigit Yuksel
  • 1,060
  • 2
  • 18
  • 35
  • Hi, i tried to add something like this : `const editorContent = loading ? () : !loading ? EditorState.createWithContent(convertFromRaw(JSON.parse(post.paragraph))) : EditorState.createEmpty();` but that didn't solve the issue – Francesco Dec 08 '20 at 15:59
  • maybe the post.paragraph is null/empty. please check that also. – Yigit Yuksel Dec 08 '20 at 17:09
  • It is not empty as you can see from last screenshot i posted above. I do get it back in console.log but after 2 undefined – Francesco Dec 09 '20 at 13:29
  • yes, that's what I am saying on my comment. you shouldn't render the content if it is undefined, that is the problem. – Yigit Yuksel Dec 09 '20 at 18:02
  • What do you mean? Why is it undefined? The post paragraph does exist in the database and if i remove draft.js i do receive it back without issues. By adding draft.js and therefore having to convert from raw (the draft.js block) and then parse, i get the issue. Any idea how to fix it? – Francesco Dec 10 '20 at 13:33
  • Your react component has called the first time when you render the page, and you initialize the hook with database calls. Thus, the first time, you create the view, you are getting undefined because you called the content without waiting for the database response. After you get the database response your database hook triggers and renders your content. That is how basically react project works. The main solution, you should render your without content after that your view will be updated automatically. – Yigit Yuksel Dec 10 '20 at 17:00
  • Yep. That's clear. But i am trying to find a solution to is. I am at the moment using async await in the router (i tested it and works fine with the other data) and i am using "loading ?" in the component to wait for the data. But still not working – Francesco Dec 10 '20 at 17:57