skip to Main Content

I’m designing a MERN application. Here’s what I have:

This is the main file:

import React, {useState, useEffect} from 'react';
import './App.css';
import TodoHeader from './components/TodoHeader';
import TodoForm from './components/TodoForm';
import TodoList from './components/TodoList';

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

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('http://localhost:8080/fetch_records');
        const data = await response.json();
        setTasks(data);
        console.log("Fetched data", data)
      } catch (error) {
        console.error('Error fetching tasks:', error);
      }
    };

    fetchData();
  }, []);
    


  return (
    <div className="App">
      <TodoHeader />
      <TodoForm />
      <TodoList item={{tasks}}/>
    </div>
  );
}

export default App;

Here’s the TodoList component:

import React, {useState, useEffect} from 'react'
import './TodoList.css'

export default function TodoList({item}) {
    const [tasks, setTasks] = useState([])
       

    useEffect(() => {
        const fetchData = async () => {
            const response = await fetch('http://localhost:8080/fetch_records')
            let data = await response.json()
            setTasks((prevTasks) => [...prevTasks, ...data]);
            //setTasks(data)
        }

        fetchData()
    }, [])

    return (
        <div>
        {/* Display the list of tasks */}
        <ul>
            {item.tasks.map((task) => (
            <li key={task._id}>{task.task} — {task.dueDate}</li>
            ))}
        </ul>
        </div>
    )

}

Form for adding tasks:

import React, { useState } from 'react'
import './TodoForm.css'
import TodoList from './TodoList';


export default function TodoForm() {
    const [tasks, setTasks] = useState([]);

    const handleSubmit = async (event) => {
        event.preventDefault(); // Prevent the default form submission behavior
        
    
        const response = await fetch('http://localhost:8080/todo-submit', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({
              task: event.target.task.value, // Access form input values using event.target
              dueDate: event.target.dueDate.value,
              isAccomplished: false
            }),
          });

        const selector = document.querySelector('.result');
        try {
            const contentType = response.headers.get('content-type');
            

            if (contentType && contentType.includes('application/json')) {
                const result = await response.json();
                

                 // Now you can use the 'result' object to dynamically update your UI
                if (result.success) {
                    selector.style.color = "green"
                    selector.insertAdjacentHTML("afterbegin", "<b>" + result.message + "</b>")
                    //console.log('Success:', result.message);
                    // Update your UI here, e.g., show a success message in a div

                    const tasksResponse = await fetch('http://localhost:8080/fetch_records'); // Replace with your actual API endpoint
                    const tasksData = await tasksResponse.json();
                    setTasks(tasksData);
                } else {
                    selector.style.color = "red"
                    selector.insertAdjacentHTML("afterbegin", "<b>" + result.errorMessage + "</b>")
                    //console.error('Error:', result.errorMessage);
                    // Handle the error, e.g., show an error message in a div
                }
            }

            else {
                const nonJsonResponse = await response.text();
                selector.style.color = "red"
                selector.insertAdjacentHTML("afterbegin", "<u>" + nonJsonResponse + "</u>")
            }

    
         
        } catch (error) {
            selector.style.color = "red"
            selector.insertAdjacentHTML("afterbegin", "<b><u>" + error + "</u></b>")
          //console.error('Error:', error);
          // Handle unexpected errors, e.g., show a generic error message in a div
        }
      };

    return(
        <>
            <form action="http://localhost:8080/todo-submit" method="post" onSubmit={handleSubmit}>
                <div class="input-group">
                    <span class="input-group-text">Enter your task to be done</span>
                    <textarea class="form-control" aria-label="With textarea" name="task" />
                </div>
                <div class="input-group">
                    <span class="input-group-text">Choose the due date for this task: </span>
                    <input type="date" class="form-control" name="dueDate" />
                </div>
                <div class="form-group">
                    <button type="submit" class="btn btn-primary">Submit data</button>
                </div>
            </form>
            <div className="result form-control"></div>
    </>
    )
}

When a new task is being added, it goes directly into the database. The TodoList component should actually re-render, because of useState and useEffect, but it doesn’t. I have tried to console.log the result of useEffect hook — it fetches data properly. I’m struggling for a number of days, and can’t get what’s going wrong.

I’ve tried to add useState and useEffect, hoping that they will trigger component re-render, but that was not the case.

2

Answers


  1. The reason why it’s not re-rendering is because the setTasks you call when you finish the POST request lives in the TodoForm component and it doesn’t affect the tasks state variable in TodoList.

    Each component’s states is scoped to that specific component, even if you have a state variable with the exact same name in other component.

    If you want to share state in a global scope, I’d suggest you read into React’s context

    A simpler alternative would be to move the handleSubmit function and the tasks state to your App component, and pass it as a prop to the children components. This way, once the post request is finished successfully and the setTasks hook is called, it’ll update the state, which will also update the props in the children and thus forcing the re-render.

    Login or Signup to reply.
  2. The TodoList component does not know the status information that has been changed in TodoForm. The status management library allows you to share the status with other components and process them to be re-rendered.

    React’s most famous state management library is Redux, but if you’re learning it for the first time, it might feel difficult.

    I recommend trying an easy-to-use library like ReactRenderState first.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search