Search code examples
javascriptreactjsreact-quill

ReactQuill (rich text) - Error: React.Children.only expected to receive a single React element child - React


I have a form and I replaced the textarea with ReactQuill based on this tutorial (https://www.youtube.com/watch?v=DjEANvaZFv0&feature=youtu.be) to get Rich Text. However once I did it, I got an error saying 'Error: React.Children.only expected to receive a single React element child' (see screenshot below).

This only came up after I replaced the textarea with ReactQuill but on the error page it shows me the code in the App.js where I've implemented google authentication with firebase and I'm not sure how the two are connected. How do I fix this?

Error page

Here's my AddArticle.js where the form is:

import React, { Component } from "react";
import firebase from "../Firebase";
import ReactQuill from "react-quill";
import "react-quill/dist/quill.snow.css";
import renderHTML from 'react-render-html';

class AddArticle extends Component {
  constructor() {
    super();
    this.ref = firebase.firestore().collection("articles");
    this.state = {
      title: "",
      content: "",
    };
  }
  onChange = (e) => {
    const state = this.state;
    state[e.target.name] = e.target.value;
    this.setState(state);
  };

  onBodyChange(e) {
    this.setState({ content: e });
  }

  onSubmit = (e) => {
    e.preventDefault();

    const { title, content } = this.state;

    this.ref
      .add({
        title,
        content,
      })
      .then((docRef) => {
        this.setState({
          title: "",
          content: "",
        });
        this.props.history.push("/");
      })
      .catch((error) => {
        console.error("Error adding document: ", error);
      });
  };

  render() {
    const { title, content } = this.state;
    return (
      <div className="container">
        <br></br>
        <br></br>
        <br></br>
        <div className="panel panel-default">
          <div className="panel-heading">
            <h3 className="panel-title text-center">Create a new article</h3>
          </div>
          <br></br>
          <br></br>
          <div className="panel-body">
            <form onSubmit={this.onSubmit}>
              <div className="form-group input-group-lg">
                <label for="title">Title:</label>
                <input
                  type="text"
                  className="form-control"
                  name="title"
                  value={title}
                  onChange={this.onChange}
                  placeholder="Title"
                />
              </div>
              <div className="form-group">
                <label for="content">Content:</label>
                <ReactQuill
                  modules={AddArticle.modules}
                  formats={AddArticle.formats}
                  name="content"
                  onChange={this.onBodyChange}
                  placeholder="Content"
                  cols="80"
                  rows="20"
                >
                  {content}
                </ReactQuill>
              </div>
              <button type="submit" className="btn btn-success">
                Submit
              </button>
            </form>
          </div>
        </div>
      </div>
    );
  }
}

// Quill Config
AddArticle.modules = {
  toolbar: [
    [{ header: [1, 2, 3, 4, 5, 6, false] }],
    [{ size: [] }],
    ["bold", "italic", "underline", "strike", "blockquote"],
    [
      { list: "ordered" },
      { list: "bullet" },
      { indent: "-1" },
      { indent: "+1" },
    ],
    ["link", "image", "video"],
    ["clean"],
    ["code-block"],
  ],
  clipboard: {
    // toggle to add extra line breaks when pasting HTML:
    matchVisual: false,
  },
};

AddArticle.formats = [
  "header",
  "font",
  "size",
  "bold",
  "italic",
  "underline",
  "strike",
  "blockquote",
  "list",
  "bullet",
  "indent",
  "link",
  "image",
  "video",
  "code-block",
];

export default AddArticle;

And here is my App.js in case it's relevant:

import React, { Component } from "react";
import "./App.css";
import Navbar from "./components/Navbar";
import Main from "./Main";
import firebase from "firebase";
import StyledFirebaseAuth from "react-firebaseui/StyledFirebaseAuth";


class App extends Component {
  state={isSignedIn:false}
  uiConfig = {
    signInFlow: "popup",
    signInOptions: [
      firebase.auth.GoogleAuthProvider.PROVIDER_ID
    ],
    callbacks: {
      signInSuccess: () => false
    }
  }

  componentDidMount = () => {
    firebase.auth().onAuthStateChanged(user => {
      this.setState({isSignedIn:!!user})
    })
  }

  render() {
    return (
      <div>
        {this.state.isSignedIn ? (
          <span>
            <Navbar />
            <Main />
          </span>
        ) :
        (
          <StyledFirebaseAuth
            uiConfig={this.uiConfig}
            firebaseAuth={firebase.auth()}
            />
        )}
      </div>
    );
  }
}

export default App;

Solution

  • As described here, I suggest passing content as ReactQuill's value instead of making it a child:

    <ReactQuill
        value={this.state.content}
        // ... other props are OK
    /> // Close the tag: no children