1

Sorry for the title not being sufficient, it's a bit hard for me to sum it up into a title.

So, I have a simple Todo app, consisting of 5 components and 2 hooks.

When I am editing a task, I call the 'editTodoForm' component (a more suitable and clear name would be updateTodoForm, sorry for that), in which I am handling the request for submitting the edit.

When the user presses 'Enter' to submit, I enter a function 'handleSubmitAndToggle' which is supposed to toggle my boolean 'isEditing', which is responsible for either showing a task in its 'normal' appearance, or in its 'editTodoForm' appearance. Once done and submitted, the function for toggling the 'isEditing' boolean variable is doing its simple job, and for some reason, in return, I get the following errors:

1)

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

react_devtools_backend.js:4026 The above error occurred in the

component:

at p at span at http://localhost:3000/static/js/bundle.js:1718:66 at Typography (http://localhost:3000/static/js/bundle.js:18021:87) at div at http://localhost:3000/static/js/bundle.js:1718:66 at ListItemText (http://localhost:3000/static/js/bundle.js:12299:82) at div at http://localhost:3000/static/js/bundle.js:1718:66 at Grid (http://localhost:3000/static/js/bundle.js:9603:87) at WEBPACK_DEFAULT_EXPORT (http://localhost:3000/static/js/bundle.js:177:5) at span at http://localhost:3000/static/js/bundle.js:1718:66 at Typography (http://localhost:3000/static/js/bundle.js:18021:87) at div at http://localhost:3000/static/js/bundle.js:1718:66 at ListItemText (http://localhost:3000/static/js/bundle.js:12299:82) at li at http://localhost:3000/static/js/bundle.js:1718:66 at ListItem (http://localhost:3000/static/js/bundle.js:12630:83) at ul at http://localhost:3000/static/js/bundle.js:1718:66 at List (http://localhost:3000/static/js/bundle.js:13018:82) at div at http://localhost:3000/static/js/bundle.js:1718:66 at Paper (http://localhost:3000/static/js/bundle.js:15164:82) at div at WEBPACK_DEFAULT_EXPORT (http://localhost:3000/static/js/bundle.js:662:5) at div at http://localhost:3000/static/js/bundle.js:1718:66 at Grid (http://localhost:3000/static/js/bundle.js:9603:87) at div at http://localhost:3000/static/js/bundle.js:1718:66 at Grid (http://localhost:3000/static/js/bundle.js:9603:87) at div at http://localhost:3000/static/js/bundle.js:1718:66 at Paper (http://localhost:3000/static/js/bundle.js:15164:82) at div at WEBPACK_DEFAULT_EXPORT (http://localhost:3000/static/js/bundle.js:367:78) at div at App

The weird part is, that when I do console.log() within the toggling function, it seems to finish all the lines within its scope, so for some reason, as it attempts to return to the 'Todo' component, it fails.

I will emphasize that in the beginning (starting with that 'screen') the same Component it fails to return to works just fine.

TodoApp.js

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";
import Grid from '@mui/material/Grid';
import {v4} from 'uuid';


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

    let [tasksVal, tasksEdit]  = useState(tasks);
    
    let handleDelete = (id2filter) => {
        let res = tasksVal.filter(task => task.id !== id2filter);
        tasksEdit(res);
    }

    let handleToggleCompletion = (todoId)=>{
        let newTasks = tasksVal.map(task => 
            task.id===todoId ? {id: task.id, txt: task.txt, completed: (!task.completed)} : task
        )

        tasksEdit(newTasks);
    }

    let handleEditTask = (id, taskTxt) => {
        let updatedTask = tasksVal.map(task => task.id === id ? {...task, txt: taskTxt} : task)
        tasksEdit(updatedTask);
    }

    console.log()

    
    //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: v4(), 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>
                <Grid container justifyContent="center" style={{marginTop: "1rem"}}>
                    <Grid item xs={12} md={8} lg={6}>
                        <TodoList 
                        tasks={tasksVal}
                        handleDelete={handleDelete} 
                        toggleCompletion={handleToggleCompletion} 
                        handleEditTask={handleEditTask} 
                        />
                        <TodoForm AddToDo={addToDo}/>
                    </Grid>
                </Grid>
            </Paper>
        </div>
    )

}

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';
import Todo from "./Todo";
import { Divider } from "@mui/material";

export default function ({tasks, handleDelete, toggleCompletion, handleEditTask}) {
    let toDos = tasks.map((task,i) =>
        <React.Fragment key={i}>
            <ListItem alignItems="flex-start">
                <ListItemText>
                    <Todo 
                    taskItself={task} 
                    handleDelete={handleDelete} 
                    handleToggleCompletion={toggleCompletion} 
                    handleEditTask={handleEditTask}/>
                </ListItemText>
            </ListItem>
            <Divider/>
         </React.Fragment>
         )
    return(
        <div>
        <Paper>
            <List>
                {toDos}
                
            </List>

        </Paper>
        </div>
    )
}

Todo.js

import React from "react";
import { red } from "@mui/material/colors"
import Checkbox from '@mui/material/Checkbox';
import Grid from '@mui/material/Grid';
import EditIcon from '@mui/icons-material/Edit';
import DeleteIcon from '@mui/icons-material/Delete';
// import ListItemSecondaryAction from '@mui/icons-material/ListItemSecondaryAction';
import { IconButton, ListItem, ListItemText, ListItemSecondaryAction, TextField, Paper } from "@mui/material";
import useToggleState from "./hooks/useToggleState";
import TodoForm from "./TodoForm";
import EditTodoForm from "./editTodoForm";



export default function ({taskItself, handleDelete, handleToggleCompletion, handleEditTask}){
    let task = <p style={{letterSpacing: "3px"}}>{taskItself.txt}</p>


    let handleDeleteToDo = () => {
        handleDelete(taskItself.id)
    }

    let toggleCompletion = () => {
        handleToggleCompletion(taskItself.id)
    }
    
    let [isEditing, toggleIsEditing] = useToggleState()
    
    return (
            <Grid container>
            {(!isEditing) ?  (<>
            <Checkbox onClick={toggleCompletion} style={{marginRight: 0}} checked={taskItself.completed}/>

            {taskItself.completed ? 
                <ListItemText style={{color: "red", letterSpacing: "3px", textDecoration:"line-through"}}>{task}</ListItemText> : 
                <ListItemText style={{color: "green", letterSpacing:"3px"}}>{task}</ListItemText> 
            }
            <IconButton aria-label="edit" onClick={toggleIsEditing}>
                <EditIcon/>
            </IconButton>
            <IconButton aria-label="delete" onClick={handleDeleteToDo}>
                <DeleteIcon/>
            </IconButton>
            </> )
            :<>
            <EditTodoForm task={taskItself} toggleEditForm={toggleIsEditing} handleEditTask={handleEditTask}/>
            </>
            }
            </Grid>

    )

}

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("");
    return (
        <div>
        <Paper style={{margin: "1rem 0", padding: "0rem 1" }}>
            <form onSubmit={e => {
                e.preventDefault();
                AddToDo(inputVal);
                inputReset();
            }}>
            <TextField fullWidth label="add new to do" margin="normal" value={inputVal} onChange={inputChange}/>
            </form>

        </Paper>
        </div>
    )

}

editTodoForm.js

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

export default function ({task, handleEditTask, toggleEditForm}) {
    const [value, handleChange, reset] = useInputStatee(task.txt)

    let handleSubmitAndToggle = (e) => {{
        e.preventDefault();
        handleEditTask(task.id, task);
        reset();
        toggleEditForm();
        console.log("SRFDWSFLDS#@$@#$@$$#???")
    }}

    return (
        <form onSubmit={handleSubmitAndToggle}>
        <TextField fullWidth  value={value} onChange={handleChange} margin="normal"/>
        </form>
    )

}

useToggleState.js

import React, {useState} from "react";

export default function (boolVar = false) {
    let [state, setState] = useState(boolVar);
    let toggleState = () => {
        setState(!state);
    }

    return [state, toggleState];
}

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];
    
}

Thanks !

1 Answer 1

1

The error you are getting generally occurs when you are trying to render something which is not an element or a string in jsx. So in your case it is giving you a error that you are trying to render an object.

let handleSubmitAndToggle = (e) => {{
        e.preventDefault();
        handleEditTask(task.id, task);
        reset();
        toggleEditForm();
        console.log("SRFDWSFLDS#@$@#$@$$#???")
    }}

In this particular code block, instead of passing the task text you are passing the task object to the edit function and then due to this instead of adding text in jsx, you are adding the object which causes this error. The fix is simple, you should just change task to task.txt

handleEditTask(task.id, task.txt);
Sign up to request clarification or add additional context in comments.

1 Comment

You found it! AAAAAAAAhhhh!! Thank you! I was on it for so long, trying to figure out where it went wrong. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.