You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中使用useRef()启用按钮及Todo列表单选按钮关联项按钮启用异常问题

Fix: Only Enable Edit/Delete Buttons for Selected Todo Item

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:

  1. Replace the global states with a single selected ID state
    Remove deleteItem and editItem, and add a state to track the selected todo's ID:

    const [selectedTodoId, setSelectedTodoId] = useState(null);
    
  2. Update the radio button handler
    Modify handleRadioBtnItem to set the selected ID, and make sure your radio button has a value and checked attribute (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.)

  3. 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 modalIsOpen with false to 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 06:52:07