React Child error from one function is referencing another function

Viewed 149

Here is now all of my code:


import styles from './Add.module.scss';
import { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import {IonPage, IonGrid, IonCol, IonRow, IonCardSubtitle, IonCard} from '@ionic/react';
import { Link } from 'react-router-dom';


const CategoryPage = () => {
  const {category} = useParams();
  const [loading, setLoading] = useState(true);
  const [loading2, setLoading2] = useState(true);
  const [categoryinfo, setCategoryinfo] = useState('');
  const [categoryname, setCategoryname] = useState('');

  useEffect(() => {
    const showjokes = ({category}) => {
      try {
        fetch(`https://fakeurl.herokuapp.com/categorypage/${category}/`, {
          method: 'GET',
          mode: 'cors',
          headers: {
            'Content-Type': 'application/json',
          },
        })
          .then(res => res.json())

          .then(data => {
            console.log('chisora', JSON.parse(data.jokes));
            setLoading2(false);
            const categoryjokes = JSON.parse(data.jokes);
            console.log('categoryjokes', categoryjokes);
            setCategoryinfo(categoryjokes);
            console.log(JSON.parse(data.jokes), '<==== here is data');
            getcatname({category});
          });
      } catch (error) {
        console.log('update, error time!', error);
        return false;
      }
    };
    showjokes({category});

    const getcatname = ({category}) => {
      try {
        fetch(`https://fakeurl.herokuapp.com/getcatname/${category}/`, {
          method: 'GET',
          mode: 'cors',
          headers: {
            'Content-Type': 'application/json',
          },
        })
          .then(res2 => res2.json())

          .then(data2 => {
            console.log('parker', JSON.parse(data2.categoryname));
            const categorynombre = JSON.parse(data2.categoryname);
            console.log('categorynombre', categorynombre.category);
            setCategoryname(categorynombre.category);
            setLoading(false);
            //console.log(JSON.parse(data.categoryname), "<==== here is data")
          });
      } catch (error) {
        console.log('update, error time!', error);
        return false;
      }
    };
  }, []);

  console.log('checking loading', loading, loading2);
  //console.log("the stuff",categoryinfo[0].joke_category)
  const stuff = categoryinfo;
  console.log('stuff', stuff);
  console.log('categoryname', categoryname);
  if (loading2 || loading) return <p>loading</p>;

  return (
    <IonPage>
      <h1>{categoryname} jokes</h1>
      <IonGrid className={styles.bottomContainer}>
        <IonRow>
          <IonCol size="12" className="ion-padding-start">
            <IonCardSubtitle className={styles.heading}>
              {categoryname} jokes
            </IonCardSubtitle>
          </IonCol>
        </IonRow>
        <div className={ styles.recentNotes }>

            { stuff.map((note, index) => {

                return (
                                

            <IonRow key={ `note_${ index }` } className="animate__animated animate__faster" id={ `noteRow_${ note.id }` }>
                <IonCol size="12">
                        <Link to={`/Update/${note.id}`}>
                                            <h2>{note}</h2>
                        </Link>
                </IonCol>
            </IonRow>
                            );
                        })}
        </div>

      </IonGrid>
    </IonPage>
  );
};

export default CategoryPage;

As you can see there are two functions in the useEffect: one to get an array of joke data and the other to get the name of the category the joke is in.

This is my error message:

Error: Objects are not valid as a React child (found: object with keys {joke, joke_name, joke_owner, joke_category, id}). If you meant to render a collection of children, use an array instead.

And it points to setLoading(false) within the getcatname function. The object that is referred to in the error is referring to the object that I get from the showjokes function.

The console.logs right before I check the two loading hooks log the data just perfectly. In other words, the functions in the useEffect do their job as far as the end product is concerned.

There is a lot I don't understand here. What is the "React child" that is being referred to? When I look around for solutions it seems to come up in render functions, but my error is simply pointing to the setLoading hook part. Why am I getting an error that seems to be referencing what is going on in another function but the error is within the other function?

Edit: Straight from postman:

data =

{
    "jokes": "[{\"joke_name\": \"scar lengthening\", \"joke_owner\": 1, \"id\": 5, \"joke_category\": 5, \"joke\": \"eventually scar tissue lengthens when they get tired of being pulled\"}, {\"joke_name\": \"bummer\", \"joke_owner\": 1, \"id\": 45, \"joke_category\": 5, \"joke\": \"Scar Tissue is a bummer\"}]"
}

data2 =

{
    "categoryname": "{\"category_owner\": 1, \"id\": 5, \"category\": \"scar tissue\"}"
}
4 Answers

So because note is an object, you can not use it as a string, unless you transform it with JSON.stringify(note) to understand the problem. But actually, if you just want the joke inside the object, you can use note.joke to access it.

Like this:

  {stuff.map((note, index) => {
        return (
            <IonRow key={`note_${ index }`} className="animate__animated animate__faster" id={ `noteRow_${ note.id }` }>
                <IonCol size="12">
                    <Link to={`/Update/${note.id}`}>
                         <h2>{note.joke}</h2>
                    </Link>
                </IonCol>
            </IonRow>
         );
  })}

Ah I see the bug now :). You have a bug in the map function:

stuff.map((note, index)....

index here is not the index of the list as you expect - rather it is another element of the list stuff. This is an object which you are rendering in full. This is why you are seeing the error about rendering an object.

your map function should just take 1 arguement. You can then get index of that element as such:

stuff.map((note) => {
   const index = stuff.indexOf(note)

})

In this part of your component's JSX:

stuff.map((note, index) => {
  //...
})

you have nested within the <Link> an <h2>:

<h2>{note}</h2>

This is the source of the problem. note here is one of the objects from the array in data.jokes from your API response.

You'll need to convert this into a string before using it as the content inside the <h2>. If you want just the joke, you can use

<h2>{note.joke}</h2>

or you can use the name of the joke:

<h2>{note.joke_name}</h2>

etc.

I hope you imported IonPage, IonGrid, IonRow, IonCol, IonCard

Related