Querying persisted React WYSIWYG data from MongoDB

Viewed 380

thanks in advance!

In summary, I am using React's WYSIWYG rich text editor, and saving the text written in the editor to a MongoDB, data is sent to a server which does the insertion. My issue is that I am unable, after following recommended code, to retrieve the stored data back successfully to display it on my page. This is for a prospective blog post site.

Below I've provided all relevant code:

My Component which sends the data to the server to insert it into MongoDB, (not in order, only relevant code):

<Editor
        editorState={editorState}
        onEditorStateChange={handleEditorChange}
        wrapperClassName="wrapper-class"
        editorClassName="editor-class"
        toolbarClassName="toolbar-class"
      />

const Practice = () => {

  const [editorState, setEditorState] = useState(
    () => EditorState.createEmpty(),
  );
  const  [convertedContent, setConvertedContent] = useState(null);
  const handleEditorChange = (state) => {
    setEditorState(state);
    convertContentToRaw();
  }

  const convertContentToRaw = () => {
    const contentState = editorState.getCurrentContent();
    setEditorState(editorState: {convertToRaw(contentState)});
  }

const stateToSend = JSON.stringify(editorState);

  try {
    const response = await axios.post('http://localhost:8080/api/insert', {
      content: stateToSend  
    }) 
  } catch(error) {
  }

In MongoDB, I've initialized 1 column for storing the WYSIWYG data, I've initialized as an empty JS object:

 const wysiwygtest = new mongoose.Schema({
    content: {
        type: {}
    }
}); 

As a result, my data is inserted into MongoDB as such, with everything desired clearly in data type such as RGBA etc. correct me if I'm wrong but I believe Mongo uses BSON, a form of binary based JSON, so this looks doable for retrieval: MongoDB Insert

Lastly, the code which is not working correctly, the retrieval. For this, I have no interest just yet in placing the data back into the text editor. Rather, I'd like to display it on the page like a typical blog post. However, I'm unable to even log to the console as of yet. I am parsing the data back to JSON using JSON.parse, converting JSON to JS object using createFromRaw and using EdiorState (even though I don't have the text editor in this component but this seems to be needed to convert the data fully..) to convert fully:

useEffect( async () => {
    try {
        const response = await axios.get('http://localhost:8080/api/query', {
            _id: '60da9673b996f54d507dbfc5'
        }); 
        
        const content = response; 
        if(content) {
            const convertedContent = 
    EditorState.createWithContent(convertFromRaw(JSON.parse(content)));
            console.log('convertedContent - ', convertedContent); 
        }
        console.log('response - ', content); 
    } catch(error) {
        console.log('error!', error);
    }
}, [])

My result for the past day and last night has been the following: "SyntaxError: Unexpected token o in JSON at position 1" and so I'm unsure what I'm doing wrong in the data retrieval, and possibly even the insertion.

Any ideas? Thanks again!

Edit: For more reference, here is what the data looks like when output to the console without a JSON.stringify, this is the full tree of data. I can see all of the relevant data is there, but how do I convert this data and display it into a div or paragraph tag, for example?

enter image description here Console log output

1 Answers

More or less figured this out, see my solution below given the aforementioned implementation:

Firstly, I think my biggest mistake was using JSON.parse(); I did away with this with success. My guess as to why this does not work (even though I inserted into MongoDB as JSON) is because we ultimately need the draft-js.Editor Object to convert the data from the DB into an object type it can understand, in order to subsequently convert into HTML successfully, with all properties.

Below is the code with captions/descriptions:

  1. Retrieve data (in useEffect before React component is rendered:

       useEffect( async () => {
         console.log('useeffect');
           try {
               const response = await axios.get('http://localhost:8080/api/query', {
                   _id: '60da9673b996f54d507dbfc5' //hard-coded id from DB for testing
               }); 
    
               const content = response.data; //get JSON data from MongoDB
               if(content) {
    
                   const rawContent = convertFromRaw(content); //convert from JSON to contentstate understood by DraftJS, for EditorState obj to use 
    
                   setEditorState(EditorState.createWithContent(rawContent)); //create EditorState based on JSON data from DB and set into component state 
    
                   let currentContentAsHTML = draftToHtml(convertToRaw(editorState.getCurrentContent())); //create object which converts contentstate understood by DraftJS into a regular vanilla JS object, then take THAT and convert into HTML with "draftToHtml" function.  Save that into our 2nd state titled "convertedContent" to be displayed on page for blog post 
                   setConvertedContent(currentContentAsHTML);
           }
       } catch(error) {
           console.log('error retrieving!', error);
       } },[convertedContent]) //ensure dependency with with convertedContent state, DB/server calls take time...
    
  2. In component render, return HTML which sets the innerHTML in the DOM using/passing the convertedContent state which we converted to proper HTML format in step 1.

return (

        <div className="blog-container" dangerouslySetInnerHTML={createMarkup(convertedContent)}></div>
  
    </div>
);
  1. In step 2, we called a function entitled, "createMarkup"; here is that method. It essentially returns HTML object using the HTML converted data originally from our database. This is a bit vulnerable it terms of malicious users being able to intercept that HTML in the DOM, however, so we use a method, "purify" from "DOMPurify" class from 'isomorphic-dompurify" library. I'm using this instead of regular DOMPurify because I am using Next JS and NEXT runs on the server side as well, and DOMPurify only expects client side:

    const createMarkup = (html) => { return { __html: DOMPurify.sanitize(html) } }

Related