0

What's the best approach to update the values of objects within an array in the state? Can't really wrap my head around hooks yet. The class approach seems to be way clearer for me at least in this case

In the below situation I'd like to change the active value on click to false within the object and also add a date value of when that happened.

handleChangeStatus doesn't work at all, I just get the 'test' on click, no errors.

const App = () => {
  const [tasks, setTasks] = useState([
    {
      text: 'Example 1',
      id: 1,
      urgent: true,
      targetDate: '2021-07-16',
      active: true,
      finishDate: null,
    },
    {
      text: 'Example 2',
      id: 2,
      urgent: false,
      targetDate: '2021-06-03',
      active: false,
      finishDate: null,
    },
    {
      text: 'Example 3',
      id: 3,
      urgent: false,
      targetDate: '2021-07-16',
      active: true,
      finishDate: null,
    },
  ]);

  const handleChangeStatus = (id) => {
    console.log('test');
    const newArr = [...tasks];
    newArr.forEach((task) => {
      if (task.id === id) {
        console.log(task.id);
        task.active = false;
        task.finishDate = new Date().getTime();
      }
    });
    setTasks(newArr);
  };
return (
    <div className="App">
      <AddTask />
      <TaskList tasks={tasks} changeStatus={handleChangeStatus} />
    </div>
  );
};

TaskList

const TaskList = (props) => {
  const active = props.tasks.filter((task) => task.active);
  const done = props.tasks.filter((task) => !task.active);

  const activeTasks = active.map((task) => (
    <Task key={task.id} task={task} changeStatus={props.changeStatus} />
  ));
  const doneTasks = done.map((task) => <Task key={task.id} task={task} />);

  return (
    <>
      <h3>Active Tasks ({active.length})</h3>
      <ul>{activeTasks}</ul>
      <hr />
      <h3>Done Tasks ({done.length})</h3>
      <ul>{doneTasks}</ul>
    </>
  );
};

Task

const Task = (props) => {
  const { text, id, urgent, targetDate, active } = props.task;

  const style = { color: 'red' };

  if (active) {
    return (
      <p>
        <strong style={urgent ? style : null}>{text}</strong>, id: {id}, target
        date: {targetDate} <button onClick={props.changeStatus}>Done</button>
      </p>
    );
  } else {
    return (
      <p>
        <strong style={urgent ? style : null}>{text}</strong>, id: {id}, target
        date: {targetDate}
      </p>
    );
  }
};
2
  • 1
    Please show how handleChangeStatus is being called. Commented May 16, 2021 at 22:32
  • I've added the rest of the code Commented May 16, 2021 at 22:36

2 Answers 2

2
<button onClick={props.changeStatus}>Done</button> 

You are sending event object to the function, try sending id

<button onClick={() => props.changeStatus(id)}>Done</button> 
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! Missed this completely... So my approach actually works, thanks!
0

Per the React Docs

If the new state is computed using the previous state, you can pass a function to setState. The function will receive the previous value, and return an updated value.

so you could do something like:

const handleChangeStatus = (id) => {
  console.log('test');
  setTask((prev)=>prev.map((task)=>{
    if(task.id === id){
      return {...task,active: false, finishDate: new Date().getTime()} 
    }  
    else{
      return task;
    }
  })
}

1 Comment

The code you posted is not wrong but the problem lies elsewhere. See the answer by @MesutUçar.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.