I have 2 componets app.js and layput.js . In app.js I have todo state which will have JSON Object which gets added when Add button from app.js is clicked. In layout.js using .map function have printed the object passed as prop from app.js. there are 2 buttons in layout.js which are deleting and updating json value where delete button works properly and re renders child component but update button is not working even though layout.js is getting re renders
app.js
import './App.css';
import Layout from './pages/layout';
import React, { useRef, useState } from 'react';
function App() {
const [todo, setTodo] = useState([]);
const titleRef = useRef();
const todoRef = useRef();
let refid=useRef(0);
console.log("render in app",refid);
function Addtodo() {
setTodo([...todo, { id:refid.current++,title: titleRef.current.value, todo: todoRef.current.value, isComplete: false }]);
}
function deleteTodo(title) {
setTodo(todo.filter(filterItem => filterItem.title !== title));
}
function updateTodo(title) {
let newtodo=todo;
for (let i=0;i<todo.length;i++ )
{
if (todo[i].title === title && !todo[i].isComplete) {
todo[i].isComplete = true;
todo[i].todo=todo[i].todo+'1';
}
}
setTodo(todo);
}
return (
<div className="App">
Title
<input ref={titleRef} id="title" type="text" />
To Do
<input ref={todoRef} id="todo" type="text" />
<button type="button" onClick={Addtodo}>Add</button>
<Layout todoArray={todo} deleteTodo={deleteTodo} updateTodo={updateTodo} />
</div>
);
}
export default App;
layout.js
import React, { useContext, useEffect } from 'react';
function Layout(props) {
const ondelete = (e) => {
props.deleteTodo(e.target.name);
}
const onupdate = (e) => {
props.updateTodo(e.target.name);
}
console.log('props',props.todoArray);
return (<>
<h1>Hello</h1>
{props.todoArray.map((todos) => {
return <div key={todos.id}>
<span><b> Title :</b> {todos.title}</span>
<span><b> To Do :</b> {todos.todo}</span>
<span><b> Is Complete :</b> {todos.isComplete.toString()}</span>
<button name={todos.title} onClick={onupdate}>Complete</button>
<button name={todos.title} onClick={ondelete}>Delete</button>
</div>
})}
</>);
}
export default Layout;
i want print tag Is Complete to True if we clicked on Complete Button
React uses shallow comparison for prop changes, this means that if the todoArray
prop is passed the same object reference, it will not re-render, even if the array elements have changes.
The solution is to call setTodo
with a new array every time.
We can ensure that a new array is created, instead of modifying the old array, by spreading the old array into your newTodo
var.
function updateTodo(title) {
let newtodo = [...todo];
for (let i = 0; i < todo.length; i++) {
if (todo[i].title === title && !todo[i].isComplete) {
todo[i].isComplete = true;
todo[i].todo = todo[i].todo + '1';
}
} setTodo(todo);
}