I have tasks and by clicking editing button or label it enable editing mode for task by swapping className. I want not to just swap className but also close editing mode for all tasks. But It seems that in this way React update object 'lists', but not actually rerender other tasks, only that clicked This my App JS:
.task{
display: block;
}
.textfield{
display: none;
}
li.editing .task{display: none;}
li.editing .textfield{
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import React, {useState} from 'react';
import { v4 as uuidv4 } from 'uuid';
import Task from './Task'
export default function App() {
const [list, setNewList] = useState(sampleList)
let newTask={
liId:uuidv4(),
liName:'Place name of Task here...',
editingActive:false
}
function setEditingLi(newName,id,editingActive){
if (editingActive){editingActive=false}
else{editingActive=true}
let newList=[...list]
let index=newList.findIndex(li=>li.liId===id)
newList[index].liName=newName
newList[index].editingActive=editingActive
setNewList(newList)
}
function toRepayActiveEditingLi(){
let newLists=list.map(task=>{
task.editingActive=false
return task
})
setNewList(newLists)
}
return (
<div>
<input onClick={()=>setNewList([...list,newTask])}
type="submit" value="Add Task" id="do_form"
/>
<br/>
<main id="general">
<ul>
{list.map(task=>{
return <Task
key={task.liId} toRepayActiveEditingLi={toRepayActiveEditingLi}
setEditingLi={setEditingLi}{...task}
/>
})}
</ul>
</main>
<br/><br/><br/><br/>
</div>
);
}
const sampleList=[]
This is my Task component:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import React, { useState} from 'react'
export default function Task(props) {
const {
liId,
liName,
editingActive,
toRepayActiveEditingLi,
setEditingLi} =props
const [liClass, toggleLiClass] = useState('li')
const [buttonName, toggleButtonName] = useState('edit')
const [currentInputValue, setInputValue] = useState('')
function handleToggleEditingClass(){
toRepayActiveEditingLi()
if(editingActive){
let value = currentInputValue
toggleLiClass('li')
toggleButtonName('edit')
if(value.trim()){
setEditingLi(currentInputValue,liId,editingActive)
}
else{
setEditingLi(liName,liId,editingActive)
}
}else{
toggleLiClass('li editing')
toggleButtonName('save')
setEditingLi(liName,liId,editingActive)
}
}
return (
<li className={liClass} id={liId}>
<label className="task"
onClick={handleToggleEditingClass}
>{liName}</label>
<textarea type="text" className="textfield"
onChange={(e)=>setInputValue(e.target.value)} defaultValue={liName}
></textarea>
<button
onClick={handleToggleEditingClass}
>{buttonName}</button>
</li>
)
}
From what I could extract from your question after playing with the sandbox I believe you want to toggle off the edit mode for other tasks when selecting any new task to edit.
You can add an effect to Task
to move the logic of toggling this state when the editingActive
prop is updated.
useEffect(() => {
if (editingActive) {
toggleLiClass("li editing");
toggleButtonName("save");
} else {
toggleLiClass("li");
toggleButtonName("edit");
}
}, [editingActive]);
function handleToggleEditingClass() {
toRepayActiveEditingLi();
if (editingActive) {
let value = currentInputValue;
if (value.trim()) {
setEditingLi(currentInputValue, liId, editingActive);
} else {
setEditingLi(liName, liId, editingActive);
}
} else {
setEditingLi(liName, liId, editingActive);
}
}