Search code examples
javascripthtmlreactjsweb-applications

"TypeError: toggleTask is not a function" in react.js


I started my first project in React.js and I'm following tutorial from youtube to learn some basics. I was fixing my problems right away but this time I can't do anything with it since yesterday.

I'm showing the code below, what's the issue? Why that error is showing up? Thank you.

This is App.js code:

import React, { useState, useRef, useEffect } from "react";
import Tasklist from "./Tasklist";
import { v4 as uuidv4 } from 'uuid';

const LOCAL_STORAGE_KEY = 'taskApp.tasks'

function App() {
  const [tasks, setTasks] = useState ([]) 
  const taskNameRef = useRef()

  useEffect(() => {
    const storedTasks = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY))
    if (storedTasks) setTasks(storedTasks)
  }, [])

  useEffect(() => {
    localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify (tasks))
  }, [tasks])
  

  function toggleTask(id) {
    const newTasks = [...tasks]
    const task = newTasks.find(task => task.id === id)
    task.complete = !task.complete
    setTasks()(newTasks)
  }

  function handleAddTask(e){
    const name = taskNameRef.current.value
    if (name === '') return
    setTasks(prevTasks => {
      return [...prevTasks, {id: uuidv4, name: name, complete: false}]
    })
    taskNameRef.current.value = null
  }

  return (
    <>
      <Tasklist tasks={tasks} toggleTask={toggleTask} />
      <input ref={taskNameRef} type="text"/>
      <button onClick={handleAddTask}>Add task</button>
      <button>Clear completed</button>
      <div>0 tasks left.</div>
    </>
  )
}

export default App;

This is Task.js code, where the issue begin:

import React from 'react'

export default function Task({ task, toggleTask }) {
    function handelTaskClick() {
    toggleTask(task.id)
    }

    return (
        <div>
            <label>

                <input type='checkbox' checked={task.complete} onChange={handelTaskClick} ></input>
                {task.name}

            </label>
        </div>
    )
}

Tasklist.js code:

import React from 'react'
import Task from './Task'

export default function Tasklist({ tasks, toggleTasks }) {
    return (
        tasks.map(task => {
            return <Task key={task.id} toggleTasks={toggleTasks} task={task} />
        })
    )
}

Solution

  • toggleTask is passed to TaskList, but TaskLists doesn't destructure it, but instead destructures toggleTasks prop, with an "s". TaskList then passes toggleTasks through to Task where it (correctly) attempts to destructure toggleTask.

    Consistently name the passed toggleTask prop.

    <Tasklist tasks={tasks} toggleTask={toggleTask} />
    

    ...

    function Tasklist ({ tasks, toggleTask }) {
      return (
        tasks.map(task => {
          return <Task key={task.id} toggleTask={toggleTask} task={task} />
        })
      )
    }
    

    ...

    function Task ({ task, toggleTask }) {
      function handelTaskClick() {
        toggleTask(task.id);
      }
    
      return (
        <div>
          <label>
            <input type='checkbox' checked={task.complete} onChange={handelTaskClick} />
            {task.name}
          </label>
        </div>
      )
    }