menu

Questions & Answers

react functional component state object not rendering in display on change

I am trying to make a react example project with a way to add a 'project', edit its contents, view, and delete it. Just to practice with setting/changing/saving data.

I'm debating if I should make this as a functional or class component, so currently I am trying with a functional component below:

https://codesandbox.io/s/quizzical-moore-5s77l0?file=/src/Projects.js:568-570

import React, { useState } from "react";

function Projects() {
  const [projects, setProjects] = useState({});

  function addProject() {
    console.log("addProject()");
    //create project
    let id = Date.now().toString().substr(8);
    let newProject = {
      name: `Upload-${id}`,
      files: {}
    };
    //update projects state
    let oldProjects = projects;
    projects[id] = newProject;
    setProjects(oldProjects);
    console.log("projects = ", projects);
  }
  return (
    <div>
      <h1>Projects.js (Functional Component)</h1>

      <button onClick={addProject}>Add Project</button>

      <div>{Object.keys(projects).length} projs</div>
    </div>
  );
}

export default Projects;

when I click add projects, I can see the project get added to the state, but my display counting how many projects there are never changes? is there additional code I need to make my dom render when the state changes? or am i using the functional component wrong?

enter image description here

Comments:
2023-01-17 00:47:33
You are mutating the projects object, which is a no-no in React. You must update the state with a new object. What you're doing now is just mutating the object that's already in the state and passing that object back in, so React has no way of knowing that the state value has changed.
Answers(1) :

Interesting question you have here. Your use of functional components isn't really flawed. It looks like you're getting caught on a reference issue.

Your <div> with the project count isn't updating because React doesn't know it needs to update it. React doesn't know it needs to update it because the reference to your projects object isn't changing. If you're confused, just search through articles on object reference equality in JavaScript.

Long story short, your issue is with this line:

let oldProjects = projects;

A quick fix would be to do this:

let oldProjects = { ...projects };

...or this to save a few lines:

setProjects(oldProjects => ({ ...oldProjects, [id]: newProject }));

There are performance reasons why these are not flawless solutions, but if this is just to get the hang of things, I don' think it's a problem.

Comments:
2023-01-17 00:47:33
Thank you! That makes sense, that I was updating the 'projects' var in such a way that react didnt pick up on it. I know this way of updating 'projects' is not efficient, seeing as im replacing the entire var essentially. And if my 'projects' object is filled with hundreds of items, what would be a more efficient way to store their data in a functional component?