Draft.js - createWithContent or convertFromRaw throwing error

孤者浪人 提交于 2020-12-13 07:40:29

问题


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. I am going to show you most of my code for clarity, apologise if it may seem too much.

This is how i set-up the project:

this is the post model

const postSchema = new mongoose.Schema(
  {
    title: {
      type: String,
      required: true,
    },
    image: { type: String, required: true },
    images: [String],
    paragraph: { type: String, required: true },
  },
  { timestamps: true }
);

const Post = mongoose.model('Post', postSchema);

export default Post;

this is the router to get and modify the post:

postRouter.get(
  '/:id',
  expressAsyncHandler(async (req, res) => {
    const post = await Post.findOne({ _id: req.params.id });
    if (post) {
      res.send(post);
    } else {
      res.status(404).send({ message: 'Post Not Found.' });
    }
  })
); 
postRouter.put(
  '/:id',
  isAuth,
  isAdmin,
  expressAsyncHandler(async (req, res) => {
    const postId = req.params.id;
    const post = await Post.findById(postId);
    if (post) {
      post.title = req.body.title;
      post.image = req.body.image;
      post.images = req.body.images;
      post.paragraph = req.body.paragraph;

      const updatedPost = await post.save();
      if (updatedPost) {
        return res
          .status(200)
          .send({ message: 'Post Updated', data: updatedPost });
      }
    }
    return res.status(500).send({ message: ' Error in Updating Post.' });
  })
);

these are the Redux actions to get the details of the post and update it:

export const updatePost = (post) => async (dispatch, getState) => {
  try {
    dispatch({ type: POST_UPDATE_REQUEST, payload: post });

    const {
      userSignin: {
        userInfo: { token },
      },
    } = getState();

    const { data } = await Axios.put(`/api/posts/${post._id}`, post, {
      headers: {
        Authorization: `Bearer ${token}`,
      },
    });
    dispatch({ type: POST_UPDATE_SUCCESS, payload: data });
  } catch (error) {
    dispatch({
      type: POST_UPDATE_FAIL,
      payload:
        error.response && error.response.data.message
          ? error.response.data.message
          : error.message,
    });
  }
};

export const detailsPost = (postId) => async (dispatch) => {
  try {
    dispatch({ type: POST_DETAILS_REQUEST, payload: postId });
    const { data } = await Axios.get(`/api/posts/${postId}`);
    dispatch({ type: POST_DETAILS_SUCCESS, payload: data });
  } catch (error) {
    dispatch({
      type: POST_DETAILS_FAIL,
      payload:
        error.response && error.response.data.message
          ? error.response.data.message
          : error.message,
    });
  }
};

and the respective reducer:

export const postDetailsReducer = (
  state = { loading: true, post: { comments: [] } },
  action
) => {
  switch (action.type) {
    case POST_DETAILS_REQUEST:
      return { ...state, loading: true };
    case POST_DETAILS_SUCCESS:
      return { loading: false, post: action.payload };
    case POST_DETAILS_FAIL:
      return { ...state, loading: false, error: action.payload };
    case POST_DETAILS_RESET:
      return { post: { comments: [] } };
    default:
      return state;
  }
};


export const postUpdateReducer = (state = { post: {} }, action) => {
  switch (action.type) {
    case POST_UPDATE_REQUEST:
      return { loading: true };
    case POST_UPDATE_SUCCESS:
      return { loading: false, success: true, post: action.payload };
    case POST_UPDATE_FAIL:
      return { loading: false, error: action.payload };
    case POST_UPDATE_RESET:
      return { post: {} };
    default:
      return state;
  }
};

and these are the reducers in the Redux store:

userDetails: userDetailsReducer,
userUpdate: userUpdateReducer,

and as last i have the screen where i am trying to update the post. Here i've set the following:

  const postId = props.match.params.id;
  const dispatch = useDispatch();
  const [id, setId] = useState('');
  const [title, setTitle] = useState('');
  const [image, setImage] = useState('');
  const [images, setImages] = useState([]);
  const [uploading, setUploading] = useState(false);
  
  const postDetails = useSelector((state) => state.postDetails);
  const { loading, post, error } = postDetails; 
  const postUpdate = useSelector((state) => state.postUpdate);
  const {
    error: errorUpdate,
    loading: loadingUpdate,
    success: successUpdate,
  } = postUpdate;

and

const editorContent = EditorState.createEmpty();

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

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

then

useEffect(() => {
    if (successUpdate) {
      dispatch({ type: POST_UPDATE_RESET });
      props.history.push(`/postlist`);
    }
    if (!post.title) {
      dispatch(detailsPost(postId));
    } else {
      setId(post._id);
      setTitle(post.title);
      setImage(post.image);
      setImages(post.images);
    }

    return () => {
      //
    };
  }, [post, successUpdate, dispatch, props.history, postId]);

here with the submitHandler i dispatch a Redux action that sends the data to the database:

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

and my Editor at the bottom of the following:

<return (
<div>
  <form className="form" onSubmit={submitHandler}>

    <div>
      <h1>Edit Post {id}</h1>
    </div>

    {loadingUpdate && <LoadingBox />}
    {errorUpdate && <MessageBox variant="error">{errorUpdate}</MessageBox>}
    {loading && <LoadingBox />}
    {error && <MessageBox variant="error">{error}</MessageBox>}
    {post.title && (
      <>
        <div>
          <label htmlFor="name">Title</label>
          <input
            id="name"
            type="text"
            placeholder="Enter title"
            value={title}  
            onChange={(e) => setTitle(e.target.value)}
          />
        </div>
      
        <div>
          <label htmlFor="image">Image Url</label>
          <input
            id="image"
            type="text"
            placeholder="Enter image url"
            value={image}
            onChange={(e) => setImage(e.target.value)}
          />
        </div>
        
        <div>
          <div />
          <div>
            <button
              onClick={() => props.history.push('/postlist')}
              type="button"
            >
              Back
            </button>{' '}
            <button className="primary" type="submit">
              Update
            </button>
          </div>
        </div>

        <div>
          <label htmlFor="paragraph">Paragraph</label>
          <Editor
            editorState={editorState.editorState}
            onEditorStateChange={handleEditorChange}
          />
        </div>
        
      </>
    )}
  </form>
</div>
)

Now, the paragraph (along with the other data for which i am not using a text editor) is successfully saved in the database and looks like this ( after JSON.stringify(convertToRaw() ):

{"blocks":[{"key":"20f7q","text":" Hello World","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":1,"length":3,"style":"bgcolor-yellow"}],"entityRanges":[],"data":{}}],"entityMap":{}}

What i want though is not an Empty editor but i want to be abe to edit an existing paragraph. Therefore i change the editorContent to the following:

const editorContent = post ?
    EditorState.createWithContent(convertFromRaw(JSON.parse(post.paragraph))) :
    EditorState.createEmpty();

It all seems fine to me, and i've even console.logged post coming from Redux store to check that i actually have data in it and that paragraph is included. Therefore i don't understand where the following error is coming from:

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

I even added the following lines to my code to take care of the cross-origin:

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();
});

To recap, it seems like i am able to create an empty editor and send the data to the database, but i get an error when i try to createWithContent eventhough the data i am trying to use does exist! I really don't know what to try because everything looks fine to me so any idea or suggestion would be highly appreciated. Many Thanks

来源:https://stackoverflow.com/questions/64808416/draft-js-createwithcontent-or-convertfromraw-throwing-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!