React中使用useRef()启用按钮及Todo列表单选按钮关联项按钮启用异常问题
Hey there! I see the issue you're facing—let's break down what's going wrong and fix it step by step.
What's Causing the Problem
Right now, you're using two global state variables (deleteItem and editItem) to control the disabled state of all your edit/delete buttons. When you click any radio button, you set these states to the clicked item's value, which means every button in the list checks against the same global value—so all buttons get enabled at once.
How to Fix It
We need to track a single "selected todo ID" instead, then only enable the buttons for the todo that matches this ID. Here's how to adjust your code:
Replace the global states with a single selected ID state
RemovedeleteItemandeditItem, and add a state to track the selected todo's ID:const [selectedTodoId, setSelectedTodoId] = useState(null);Update the radio button handler
ModifyhandleRadioBtnItemto set the selected ID, and make sure your radio button has avalueandcheckedattribute (so users can see which item is selected):const handleRadioBtnItem = (event) => { setSelectedTodoId(event.target.value); };In the radio button JSX:
<input className='Rdo' type='radio' value={todo.id} checked={selectedTodoId === todo.id.toString()} onClick={handleRadioBtnItem} />(Note: Radio button values are strings, but your todo IDs are numbers—so we use
.toString()to match types.)Adjust the disabled condition for edit/delete buttons
For each button, check if the current todo's ID matches the selected ID. If yes, enable the button; otherwise, keep it disabled:<button className='Edit-Btn' onClick={()=>{setTodoEditing(todo.id);setModalIsOpen(true)}} disabled={selectedTodoId !== todo.id.toString()} > <AiFillEdit/> </button> <button className='Del-Btn' onClick={()=>deleteTodo(todo.id)} disabled={selectedTodoId !== todo.id.toString()} > <AiFillDelete/> </button>
Full Modified Code
Here's the complete updated component with all fixes (plus a few extra quality-of-life improvements):
import React,{useState} from 'react'; import Modal from 'react-modal'; import {AiFillDelete,AiFillEdit} from 'react-icons/ai'; import './App.css'; Modal.setAppElement('#root') function App() { const [todos,setTodos] = useState([{id:0,text:"item1"},{id:1,text:"item2"}]) const [todo,setTodo] = useState("") const [todoEditing,setTodoEditing] = useState(null) const [editingText,setEditingText] = useState("") // Replaced deleteItem and editItem with a single selected ID tracker const [selectedTodoId, setSelectedTodoId] = useState(null); const [modalIsOpen,setModalIsOpen] = useState(false) // Initialized with false for consistency function handleSubmit(e){ e.preventDefault() const newTodo = { id:todos.length, text : todo, } // Cleaned up array concatenation syntax setTodos([newTodo, ...todos]) setTodo("") } function deleteTodo(id){ const updateTodos = [...todos].filter((todo)=>todo.id !== id) setTodos(updateTodos) // Clear selected ID if the deleted item was the selected one if (selectedTodoId === id.toString()) { setSelectedTodoId(null); } } function editTodo(id){ // Avoid mutating the original todo object (best practice in React) const updateTodos = [...todos].map((todo) => { if(todo.id===id){ return {...todo, text: editingText} } return todo }) setTodos(updateTodos) setTodoEditing(null) setEditingText("") setModalIsOpen(false) } const handleRadioBtnItem = (event) =>{ setSelectedTodoId(event.target.value); } return ( <div className="App"> <div className='todo-head'> <h1 className='ForHeading'>Todo List</h1> <form onSubmit={handleSubmit}> <input className='User-Input' type='text' onChange={(e)=>setTodo(e.target.value)} value={todo}/> <button className='Add-Btn' type='submit' disabled={!todo}>Add Todo</button> </form> </div> {todos.map((todo)=> <ul className='ul-Style' key={todo.id} id={todo.id}> <input className='Rdo' type='radio' value={todo.id} checked={selectedTodoId === todo.id.toString()} onClick={handleRadioBtnItem} /> {todoEditing === todo.id ? ( <div> <Modal isOpen={modalIsOpen} shouldCloseOnOverlayClick={false} style={ { overlay:{ backgroundColor:'gray' }, content:{ textAlign:'center' } } } > <h2>Edit Items</h2> <input type='text' onChange={(e)=> setEditingText(e.target.value)} value={editingText}/> <div> {/* Disable save button if there's no edit text */} <button onClick={()=>editTodo(todo.id)} disabled={!editingText}>Save</button> <button onClick={()=>setModalIsOpen(false)}>Close</button> </div> </Modal> {todo.text} </div> ) : ( <p>{todo.text}</p> ) } <button className='Edit-Btn' onClick={()=>{setTodoEditing(todo.id);setModalIsOpen(true)}} disabled={selectedTodoId !== todo.id.toString()} > <AiFillEdit/> </button> <button className='Del-Btn' onClick={()=>deleteTodo(todo.id)} disabled={selectedTodoId !== todo.id.toString()} > <AiFillDelete/> </button> </ul>)} </div> ); } export default App;
Extra Improvements Included
- Cleaned up array syntax for adding new todos
- Initialized
modalIsOpenwithfalseto avoid undefined state issues - Prevented direct mutation of todo objects in the edit function (React best practice)
- Added logic to clear the selected ID when the corresponding todo is deleted
- Disabled the modal's "Save" button if no edit text is entered
内容的提问来源于stack exchange,提问作者Sai Venkat

