Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why is React not re-rendering on setState?

I have a React project for a todo list. When you click to delete a task, it successfully sends the request to the API and removes the task from the database. After that, I request the tasks again and then setState with the new task list. After using setState, nothing updates on the website until you refresh the page.

What am I doing wrong? I’m brand new to React so any explanation, I would be very grateful for!

App.js:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import React from 'react';
import taskApi from "../api/task-api";
import TaskList from "./TaskList";
import {Button, Container} from "react-bootstrap";

class App extends React.Component {
    state = {
        tasks: [],
    }

    componentDidMount() {
        taskApi.get('/tasks').then(
            res => {
                const tasks = res.data.data;
                this.setState({tasks})
            }
        );

    }


    render() {
        return(
            <Container>
                <h1>Task Manager</h1>
                <Button variant="primary" size="lg" className="add-task-button">Add Task</Button>
                <TaskList tasks={this.state.tasks} />
            </Container>
        );
    }
}

export default App;

TaskList.js:

import React from 'react';
import Table from 'react-bootstrap/Table'

import TaskItem from "./TaskItem";

class TaskList extends React.Component {
    render() {
        return(
                <Table striped bordered hover>
                    <thead>
                        <tr key="header">
                            <th>ID #</th>
                            <th>Task Name</th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                    {this.props.tasks.map((task) => {
                        return <TaskItem task={task} key={task.id} />
                    })}
                    </tbody>
                </Table>
        );
    }
}

export default TaskList;

TaskItem.js:

import React from 'react';
import {Button, Modal} from "react-bootstrap";
import taskApi from "../api/task-api";


class TaskItem extends React.Component {

    constructor() {
        super();
        this.state = {
            show: false,
        };
    }

    showModal() {
        this.setState({show: true});
    }

    closeModal() {
        this.setState({show: false});
    }

    deleteTask(task_id) {
        this.setState({show: false});
        taskApi.delete('/task/' + task_id).then(()=>{
            taskApi.get('/tasks').then(
                res => {
                    const tasks = res.data.data;
                    this.setState({tasks})
                }
            );
            }
        );
    }

    render() {
        return(
                <tr>
                    <td>{this.props.task.id}</td>
                    <td>{this.props.task.task_name}</td>
                    <td>
                        <Button variant="success" className="task-action-button">Complete</Button>
                        <Button variant="secondary" className="task-action-button">Edit</Button>
                        <Button variant="danger" className="task-action-button" onClick={()=>{this.showModal()}}>Delete</Button>
                        <Modal show={this.state.show}>
                            <Modal.Header>Confirm</Modal.Header>
                            <Modal.Body>
                                Are you sure you want to delete this task?
                                <br/><br/>
                                <strong>Task:</strong>
                                <br/>
                                {this.props.task.task_name}
                            </Modal.Body>
                            <Modal.Footer>
                                <Button variant="secondary" onClick={()=>{this.closeModal()}}>Cancel</Button>
                                <Button variant="danger" onClick={()=>{this.deleteTask(this.props.task.id)}}>Delete</Button>
                            </Modal.Footer>
                        </Modal>
                    </td>
                </tr>
        );
    }
}

export default TaskItem;

>Solution :

Right now, you’re doing

class TaskItem extends React.Component {
    deleteTask(task_id) {
        // ...
        this.setState({tasks})

You’re setting state in TaskItem – but you never reference this.state.tasks in TaskItem. The tasks state exists in the parent, inside your class App. So, updating the state in the child component doesn’t do anything – you need to update the state in the parent instead.

Put the methods that need to manipulate the parent’s state in the parent, and then pass them down.

class App extends React.Component {
    deleteTask = (task_id) => {
        taskApi.delete('/task/' + task_id).then(()=>{
             // ...

App’s render method:

<TaskList tasks={this.state.tasks} deleteTask={this.deleteTask} />

TaskList’s render method:

return <TaskItem task={task} key={task.id} deleteTask={this.props.deleteTask} />

And finally in TaskItem:

deleteTask(task_id) {
    this.setState({show: false});
    this.props.deleteTask(task_id);
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading