4 回答

TA贡献1848条经验 获得超10个赞
您不需要更新状态,当单击任何按钮时,只需在按钮上显示不同的文本。
在包含所有数据的列表的父元素上添加单击事件侦听器,并检查触发click
事件的元素是否为复制按钮。如果是,请更改其文本并设置一个计时器,将文本恢复为“复制”
演示:
const url = 'https://jsonplaceholder.typicode.com/todos';
function App() {
const [todos, setTodos] = React.useState([]);
React.useEffect(() => {
fetch(url)
.then(res => res.json())
.then(todos => setTodos(todos))
.catch(err => console.log(err.message));
}, []);
return (
<div className="App">
<TodoList todos={todos}/>
</div>
);
}
function TodoList(props) {
function changeBtnText(event) {
const target = event.target;
if (target.matches("button")) {
target.textContent = "Copied";
setTimeout(() => (target.textContent = "Copy"), 1000);
}
}
return (
<div className="todoList" onClick={changeBtnText}>
{props.todos.map(t => (
<Todo key={t.id} {...t} />
))}
</div>
);
}
function Todo({ title, completed }) {
return (
<div className="todo">
<span>TItle: {title}</span>
<button>Copy</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
.App {
font-family: sans-serif;
text-align: center;
}
.todo {
box-shadow: 0 0 2px rgba(0, 0, 0, 0.3);
margin: 10px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 10px;
}
.todo button {
padding: 5px 10px;
margin: 10px 0 0 0;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
您还可以在 Codesandbox 上查看此演示

TA贡献1805条经验 获得超9个赞
import React, { useEffect, useState, useCallback, useRef } from 'react'
import { range } from 'lodash-es'
const App = () => {
const [items, setItems] = useState(
range(100).map((val) => ({ id: val, val, text: 'Copy' })),
)
const [copiedItem, setCopiedItem] = useState<number | undefined>(undefined)
const timeout = useRef<number | undefined>(undefined)
useEffect(() => {
if (copiedItem) {
setItems((itemsState) =>
itemsState.map((item) =>
item.id === copiedItem
? { ...item, text: 'Copied' }
: { ...item, text: 'Copy' },
),
)
} else {
setItems((itemsState) =>
itemsState.map((item) => ({ ...item, text: 'Copy' })),
)
}
}, [copiedItem])
const handleClick = useCallback(
(itemId) => () => {
if (timeout.current) {
window.clearTimeout(timeout.current)
}
setCopiedItem(itemId)
timeout.current = window.setTimeout(() => {
setCopiedItem(undefined)
}, 1000)
},
[],
)
return (
<div>
{items.map((item) => (
<div key={item.id} className="mb-4">
<span className="mr-2">{item.val}</span>
<button className="p-2 bg-gray-100" onClick={handleClick(item.id)}>
{item.text}
</button>
</div>
))}
</div>
)
}
export default App
您可以使用另一种状态copiedItem来存储要复制的项目的 id 或索引。在 中useEffect我们可以寻找更改copiedItem以设置要复制的文本。
除此之外,我们还需要对上一个超时的引用,以便我们可以在触发下一个项目超时之前清除它。

TA贡献1803条经验 获得超6个赞
所以我尝试使用@Agney 建议在 setState 中使用回调。这是codesanbox链接https://codesandbox.io/s/quirky-dubinsky-lm03x?file=/src/App.js
所以基本上我们在 setstate 回调中检查索引以最初将其设置为复制,在超时回调中我们再次检查相同的索引以设置回复制。
添加回答
举报