Home > Software design >  Errors while trying to convert Class Component to Functional
Errors while trying to convert Class Component to Functional

Time:09-10

I'm trying to convert the class components in my Reactjs ToDo app to functional components. Here is one of the my original components:

import React, { Component } from "react";
import TaskDataService from "../services/task.service";
import FadeIn from 'react-fade-in';
import { Link } from "react-router-dom";

export default class TasksList extends Component {
    constructor(props) {
        super(props);
        this.onChangeSearchTitle = this.onChangeSearchTitle.bind(this);
        this.retrieveTasks = this.retrieveTasks.bind(this);
        this.refreshList = this.refreshList.bind(this);
        this.setActiveTask = this.setActiveTask.bind(this);
        this.removeAllTasks = this.removeAllTasks.bind(this);
        this.searchTitle = this.searchTitle.bind(this);

        this.state = {
            Tasks: [],
            currentTask: null,
            currentIndex: -1,
            searchTitle: ""
        };
    }

    componentDidMount() {
        this.retrieveTasks();
    }

    onChangeSearchTitle(e) {
        const searchTitle = e.target.value;

        this.setState({
            searchTitle: searchTitle
        });
    }

    retrieveTasks() {
        TaskDataService.getAll()
            .then(response => {
                this.setState({
                    Tasks: response.data
                });
                console.log(response.data);
            })
            .catch(e => {
                console.log(e);
            });
    }

    refreshList() {
        this.retrieveTasks();
        this.setState({
            currentTask: null,
            currentIndex: -1
        });
    }

    setActiveTask(Task, index) {
        this.setState({
            currentTask: Task,
            currentIndex: index
        });
    }

    removeAllTasks() {
        TaskDataService.deleteAll()
            .then(response => {
                console.log(response.data);
                this.refreshList();
            })
            .catch(e => {
                console.log(e);
            });
    }

    searchTitle() {
        this.setState({
            currentTask: null,
            currentIndex: -1
        });

        TaskDataService.findByTitle(this.state.searchTitle)
            .then(response => {
                this.setState({
                    Tasks: response.data
                });
                console.log(response.data);
            })
            .catch(e => {
                console.log(e);
            });
    }

    render() {
        const { searchTitle, Tasks, currentTask, currentIndex } = this.state;

        return (
            <FadeIn>
                <div className="list row">
                        <div className="col-md-8">
                            <div className="input-group mb-3">
                                <input
                                    type="text"
                                    className="form-control"
                                    placeholder="Search by title"
                                    value={searchTitle}
                                    onChange={this.onChangeSearchTitle}
                                />
                                <div className="input-group-append">
                                    <button
                                        className="btn btn-outline-secondary"
                                        type="button"
                                        onClick={this.searchTitle}
                                    >
                                        Search
                                    </button>
                                </div>
                            </div>
                        </div>
                        <div className="col-md-6">
                            <h4>Tasks List</h4>

                            <FadeIn>
                                <ul className="list-group">
                                    {Tasks &&
                                        Tasks.map((Task, index) => (
                                            <li
                                                className={
                                                    "list-group-item "  
                                                    (index === currentIndex ? "active" : "")
                                                }
                                                onClick={() => this.setActiveTask(Task, index)}
                                                key={index}
                                            >
                                                <div className="align-left">
                                                    {Task.title}
                                                </div>

                                                <div className="align-right">
                                                    {Task.startDate.toString().split("T")[0]}
                                                </div>
                                            </li>
                                        ))}
                                </ul>
                            </FadeIn>

                            <button
                                className="m-3 btn btn-sm btn-danger"
                                onClick={this.removeAllTasks}
                            >
                                Remove All
                            </button>
                        </div>
                        <div className="col-md-6">
                            {currentTask ? (
                                <FadeIn>
                                    <div>
                                        <h4>Task</h4>
                                        <div>
                                            <label>
                                                <strong>Title:</strong>
                                            </label>{" "}
                                            {currentTask.title}
                                        </div>
                                        <div>
                                            <label>
                                                <strong>Description:</strong>
                                            </label>{" "}
                                            {currentTask.description}
                                        </div>
                                        <div>
                                            <label>
                                                <strong>Status:</strong>
                                            </label>{" "}
                                            {currentTask.completed ? "Completed" : "Pending"}
                                        </div>
                                        <div>
                                            <label>
                                                <strong>Due Date:</strong>
                                            </label>{" "}
                                            {currentTask.startDate.split("T")[0]}
                                        </div>

                                        <Link
                                            to={"/Tasks/"   currentTask.id}
                                            className="badge badge-warning"
                                        >
                                            Edit
                                        </Link>
                                    </div>
                                </FadeIn>
                            ) : (
                                <div>
                                    <br />
                                    <p>Please click on a Task...</p>
                                </div>
                            )}
                        </div>
                </div>
            </FadeIn>
        );
    }
}

...and my attempt to convert it into a functional component:

import React, { useState, useEffect } from "react";
import TaskDataService from "../services/task.service";
import FadeIn from 'react-fade-in';
import { Link } from "react-router-dom";


function TasksList() {
    const [Tasks, setTasks] = useState([]);
    const [currentTask, setCurrentTask] = useState(null);
    const [currentIndex, setCurrentIndex] = useState(-1);
    const [searchTitle, setSearchTitle] = useState("");

    useEffect(() => {
        retrieveTasks();
    });

    const onChangeSearchTitle = (e) => {
        const searchTitle = e.target.value;

        setSearchTitle({
            searchTitle: searchTitle
        });
    }

    const retrieveTasks = () => {
        TaskDataService.getAll()
            .then(response => {
                setTasks({
                    Tasks: response.data
                });
                console.log(response.data);
            })
            .catch(e => {
                console.log(e);
            });
    }

    const refreshList = () => {
        retrieveTasks();
        setTasks(null);
        setCurrentIndex(-1);
    }

    const setActiveTask = (Task, index) => {
        setTasks( Task );
        setCurrentIndex( index );
    }

    const removeAllTasks = () => {
        TaskDataService.deleteAll()
            .then(response => {
                console.log(response.data);
                refreshList();
            })
            .catch(e => {
                console.log(e);
            });
    }

    const onSearchTitle = () => {
        setTasks(null);
        setCurrentIndex(-1);

        TaskDataService.findByTitle(searchTitle)
            .then(response => {
                setTasks(response.data)
                console.log(response.data);
            })
            .catch(e => {
                console.log(e);
            });
    }

    return (
        <FadeIn>
            <div className="list row">
                <div className="col-md-8">
                    <div className="input-group mb-3">
                        <input
                            type="text"
                            className="form-control"
                            placeholder="Search by title"
                            value={searchTitle}
                            onChange={onChangeSearchTitle}
                        />
                        <div className="input-group-append">
                            <button
                                className="btn btn-outline-secondary"
                                type="button"
                                onClick={onSearchTitle}
                            >
                                Search
                            </button>
                        </div>
                    </div>
                </div>
                <div className="col-md-6">
                    <h4>Tasks List</h4>

                    <FadeIn>
                        <ul className="list-group">
                            {Tasks &&
                                Tasks.map((Task, index) => (
                                    <li
                                        className={
                                            "list-group-item "  
                                            (index === currentIndex ? "active" : "")
                                        }
                                        onClick={() => setActiveTask(Task, index)}
                                        key={index}
                                    >
                                        <div className="align-left">
                                            {Task.title}
                                        </div>

                                        <div className="align-right">
                                            {Task.startDate.toString().split("T")[0]}
                                        </div>
                                    </li>
                                ))}
                        </ul>
                    </FadeIn>

                    <button
                        className="m-3 btn btn-sm btn-danger"
                        onClick={removeAllTasks}
                    >
                        Remove All
                    </button>
                </div>
                <div className="col-md-6">
                    {currentTask ? (
                        <FadeIn>
                            <div>
                                <h4>Task</h4>
                                <div>
                                    <label>
                                        <strong>Title:</strong>
                                    </label>{" "}
                                    {currentTask.title}
                                </div>
                                <div>
                                    <label>
                                        <strong>Description:</strong>
                                    </label>{" "}
                                    {currentTask.description}
                                </div>
                                <div>
                                    <label>
                                        <strong>Status:</strong>
                                    </label>{" "}
                                    {currentTask.completed ? "Completed" : "Pending"}
                                </div>
                                <div>
                                    <label>
                                        <strong>Due Date:</strong>
                                    </label>{" "}
                                    {currentTask.startDate.split("T")[0]}
                                </div>

                                <Link
                                    to={"/tasks/"   currentTask.id}
                                    className="badge badge-warning"
                                >
                                    Edit
                                </Link>
                            </div>
                        </FadeIn>
                    ) : (
                        <div>
                            <br />
                            <p>Please click on a Task...</p>
                        </div>
                    )}
                </div>
            </div>
        </FadeIn>
    );
}

export default TasksList;

But when running my frontend, the page fails to load with this error seeming like the big one: "Uncaught TypeError: Tasks.map is not a funtion". Console points to this segment as the culprit:

<ul className="list-group">
                            {Tasks &&
                                Tasks.map((Task, index) => (
                                    <li...

So it doesn't like Tasks.map. I've spent a lot of time on research and can't figure out what the problem is. Any ideas?

CodePudding user response:

It seems that you are settings in multiple part of your code with setTasks a value other than an array which eventually can leads to Tasks.map triggering an error.

For exemple in the function retreiveTasks you are setting Tasks to an object.

  • Related