Home > Net >  ReactJS Hooks - investigation code's 'Objects are not valid as a React child' error a
ReactJS Hooks - investigation code's 'Objects are not valid as a React child' error a

Time:10-06

So, I have been attempting to read about this error ( Objects are not valid as a React child. If you meant to render a collection of children, use an array instead and here https://www.g2i.co/blog/understanding-the-objects-are-not-valid-as-a-react-child-error-in-react ), and I (think I) understand it's an issue of passing a 'complex' object to react's child component/passing a JS object to a component. (am I correct?)

I have located where my issue lays in my code, but I cannot really understand why would the variable be interpreted as a complex object in the first place.

The issue occurs when I'm trying to create at TodoApp.js, addToDo() function. This function is later on transferred to a child component 'TodoForm.js', so it could, on handleSubmit, call his father's function addToDo():

In addToDo(), if I edit, where I add a new element, the field txt 's value to a string for example, it works.

TodoApp.js (in code's comments I have pointed out where is exactly the issue)

import React, {useState} from "react";
import TodoList from './TodoList';
import Paper from '@mui/material/Paper';
import List from '@mui/material/List';
import TextField from '@mui/material/TextField';
import ListItem from '@mui/material/ListItem';
import Divider from '@mui/material/Divider';
import ListItemText from '@mui/material/ListItemText';
import { AppBar, Toolbar, Typography } from "@mui/material";
import { fontWeight } from "@mui/system";
import TodoForm from "./TodoForm";


export default function () {
    let tasks = [
        {id: 1, txt: "thisisTask1", completed: true},
        {id: 2, txt: "thisisITask2", completed: false},
        {id: 3, txt: "SO ORIGINAL", completed: false}
    ]

    let [tasksVal, tasksEdit]  = useState(tasks);


    const tasksTxts = tasksVal.map((task) => 
        <><ListItem><ListItemText>{task.txt}</ListItemText></ListItem> <Divider/></>
        )
    
    
    //issue seems to lay here - if I change txt: "texthere" - no errors (but doesn't add the task either) 
    let addToDo = (taskTxt) => { // a function to later on send to TodoForm for when a Submit occures.
        tasksEdit([...tasksVal, {  id: 4, txt: {taskTxt}, completed: false }])
    };

    return(

        <div>
            <Paper style={{padding: 0, margin: 0, height: "100vh", backgroundColor: "whitesmoke"}}>
                <AppBar position='static' style={{height: "64px"}} color="primary">
                    <Toolbar>
                        <Typography style={{letterSpacing: "3px", fontSize: "40px"}}>Todos with Hooks!</Typography>
                    </Toolbar>
                </AppBar>
                <TodoList tasksTxts={tasksTxts}/>
                <TodoForm AddToDo={addToDo}/>
                
            </Paper>
        </div>
    )

}

TodoForm.js

import React from "react";
import useInputStatee from "./hooks/useInputStatee";
import { Paper, TextField } from "@mui/material";

export default function ({AddToDo}) {
    const [inputVal, inputChange, inputReset] = useInputStatee("");
    console.log(inputVal)
    return (
        <div>
        <Paper>
            <form onSubmit={e => {
                AddToDo(inputVal);
                // inputReset();
            }}>
            <TextField value={inputVal} onChange={inputChange}/>
            </form>
                <p>{inputVal}</p>

        </Paper>
        </div>
    )

}

useInputStatee.js

import React, {useState} from "react";
export default function (initVal) {
    let [value, setValue] = useState(initVal);

    let handleChange = (e) => { // when we get from a form ... we get an e.target.value
        setValue(e.target.value);
    }

    let reset = () => { setValue(""); }

    return [value, handleChange, reset];
    
}

TodoList.js

import React from "react";
import Paper from '@mui/material/Paper';
import List from '@mui/material/List';
import TextField from '@mui/material/TextField';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';

export default function ({tasksTxts}) {

return(
    <div>
        <Paper>
            <List>
                {tasksTxts}
            </List>
        </Paper>
     </div>
    )
}

Thanks in advance!

CodePudding user response:

The issue is in tasksTxts, it's rendering an object instead of valid JSX.

const tasksTxts = tasksVal.map((task) => 
  <>
    <ListItem>
      <ListItemText>
        {task.txt} // <-- task.txt is object { taskTxt }
      </ListItemText>
    </ListItem>
    <Divider/>
  </>
);

...

let addToDo = (taskTxt) => {
  tasksEdit([
    ...tasksVal,
    {
      id: 4,
      txt: { taskTxt }, // <-- caused here
      completed: false
    }
  ])
};

The tasksTxts needs to access into the additional taskTxt property:

const tasksTxts = tasksVal.map((task) => 
  <>
    <ListItem>
      <ListItemText>
        {task.txt.taskTxt}
      </ListItemText>
    </ListItem>
    <Divider/>
  </>
);

Or the task.txt just needs to be the value you want to display:

let addToDo = (taskTxt) => {
  tasksEdit(tasksVal => [
    ...tasksVal,
    { id: 4, txt: taskTxt, completed: false }
  ])
};

Unrelated Suggestion

You will want to also add a valid React key to the mapped tasks.

Example:

const tasksTxts = tasksVal.map((task) => 
  <React.Fragment key={task.id}> // <-- Valid React key
    <ListItem>
      <ListItemText>
        {task.txt}
      </ListItemText>
    </ListItem>
    <Divider/>
  </React.Fragment>
);

CodePudding user response:

You are correct, the error is inside the addToDo() function:

    let addToDo = (taskTxt) => {
        tasksEdit([...tasksVal, {  id: 4, txt: {taskTxt}, completed: false }])
        //                                     ^^^^^^^^^ the error is here
    };

taskTxt is being wrapped inside another object instead of just being put on directly.

So the correct version of this code is:

        tasksEdit([...tasksVal, {  id: 4, txt: taskTxt, completed: false }])
        //                                     ^^^^^^^ note no wrapping braces any more
  • Related