Home > Enterprise >  useState is not updating the DOM in my React todo list app
useState is not updating the DOM in my React todo list app

Time:01-03

I am trying to learn the basics of React and thought that making a todo list app would be a great first project to help me learn.

I have a basic form to add todos, but, when enter is clicked, the DOM does not change. Here is my app.js code, which I think is where my error might be:

import AddTodoForm from './components/AddTodoForm.js';
import TodoList from './components/TodoList.js';
import { dataList } from './components/AddTodoForm.js';
import { useState } from 'react';

function App() {

  const[list, setList] = useState([]);

  function update(){
    setList(dataList);
    console.log(list);
    console.log("update function has run.")
  }

  return (
    <div>

      <AddTodoForm update = {update} />

      <h1>My Todos</h1>
        
      <TodoList todos={list} />    

    </div>
  );
}

export default App;

Here is the code for TodoList.js as somebody had asked for it:

import Todo from './Todo';

function TodoList(props) {
    return (
        <ul>
            {props.todos.map((todo) => (
                <Todo
                key = {todo.id}
                id= {todo.id}
                text= {todo.text}
                />
            ))}
        </ul>
    )
}

export default TodoList;

here is the AddTodoForm.js:

import { useRef, useState } from 'react';


var idCounter = 1;

export const dataList = [];

function AddTodoForm(props){

    const titleInputRef = useRef();


    function submitHandler(event){
        event.preventDefault();

        const enteredTitle= titleInputRef.current.value;

        const todoData = {
            text: enteredTitle,
            id: idCounter,
        }

        idCounter  ;

        console.log(todoData);
        dataList.push(todoData);

       
        
    }


    return (
        <div className="card">
            <h2>Add New Todos</h2>

            <form onSubmit={(event) => {submitHandler(event); }}>
                <div>
                    <label htmlFor="text">New Todo: </label>
                    <input type="text" required id="text" ref={titleInputRef}></input>
                </div> <br />

                <div>
                    <button className="btn" onClick = {props.update}>Add Todo</button>
                </div>
            </form>

        </div>
    )
}

export default AddTodoForm;

I have checked the log and the update function runs. Also, if I make a slight change to my code, the todos I had entered will appear on the screen but I am not sure why the DOM does not change when the update function runs.

This is my first post on here so I wasn't sure how much of my code to include. Please ask if you need the code from my other components.

Many thanks in advance :)

CodePudding user response:

Calling dataList.push(todoData) won't change dataList itself, only its content, and React doesn't check the content to update the DOM. You could use the Spread syntax to have a completely new dataList.

You could even get ride of that dataList, and use the empty array given to useState. Update your update function slightly, and it should work:

import AddTodoForm from "./components/AddTodoForm.js";
import TodoList from "./components/TodoList.js";
import { useState } from "react";

function App() {
  const [list, setList] = useState([]);

  function update(todo) {
    setList([...list, todo]);
  }

  return (
    <div>
      <AddTodoForm update={update} />
      <h1>My Todos</h1>
      <TodoList todos={list} />
    </div>
  );
}

export default App;
import { useRef } from "react";

let idCounter = 1;

function AddTodoForm(props) {
  const titleInputRef = useRef();

  function submitHandler(event) {
    event.preventDefault();

    const enteredTitle = titleInputRef.current.value;

    const todoData = {
      text: enteredTitle,
      id: idCounter,
    };

    idCounter  ;

    props.update(todoData);
  }

  return (
    <div className="card">
      <h2>Add New Todos</h2>

      <form onSubmit={submitHandler}>
        <div>
          <label htmlFor="text">New Todo: </label>
          <input type="text" required id="text" ref={titleInputRef}></input>
        </div>
        <br />
        <div>
          <button className="btn">Add Todo</button>
        </div>
      </form>
    </div>
  );
}

export default AddTodoForm;

CodePudding user response:

In App.js, I have removed the update function and instead sent the list and setList as props to the AddTodoForm component.

import AddTodoForm from './components/AddTodoForm.js';
import TodoList from './components/TodoList.js';
import { useState } from 'react';

function App() {

  const[list, setList] = useState([]);

  return (
    <div>

      <AddTodoForm setList = {setList} list = {list}/>

      <h1>My Todos</h1>
        
      <TodoList todos={list} />    

    </div>
  );
}

export default App;

In ./components/AddTodoForm.js add this peice of code inside the AddTodoForm function.

const update = ()=>{
    props.setList(datalist);
    console.log(props.list);
    console.log("The update function has run.")
}

I hope this might help.

CodePudding user response:

Happy New Year. I am glad to give my advice for your problem. I am going to post my opinion to help you with my humble knowledge about react. In your above code, you cannot render updated state(list) to reflect TodoList component. In hook, useEffect insteads 2 component lifecycles of class component idea. I mean, you should reflect useEffect with updated states(list). useEffect is similar to componentDidMount and componentDidUpdate: Like this...

enter code here
   useEfect(()=>{
      setList(dataList);
      console.log(list);
      console.log("update function has run.")
   },[list])
  

Hope this will help you. Thanks for reading.

  • Related