亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

ReactJS 如何使用狀態鉤子獲取超時的文本更改按鈕列表?

ReactJS 如何使用狀態鉤子獲取超時的文本更改按鈕列表?

守著一只汪 2022-10-21 15:37:41
這可能會令人困惑,但我感謝您的幫助。我基本上有一個數據列表,每個數據旁邊都有一個“復制”按鈕。單擊時,我希望它更改為“已復制!” 500 毫秒,然后返回“復制”。我的設置如下:我有一個數組,其中包含我作為道具傳遞給組件的數據列表(比如說數組 x)。使用這個數組,我創建了一個 useEffect 鉤子(當數據數組 x 更新時更新)。這個鉤子使用原始數組長度的新數組(比如說數組 y)和文本“復制”更新一個新狀態。據我所知,似乎工作得很好,現在我的問題出在哪里:然后我為創建新數組的按鈕創建一個處理程序,使用點符號展開并將按鈕的索引從“復制”更新為“抄襲!”。然后超時將其恢復為“復制”(下面的代碼)。效果很好,但你懷疑我有一個錯誤。如果我在另一個按鈕上太快地點擊復制,我最終會將原來的“復制”按鈕卡在那里。正如我猜測的那樣,我更新狀態的速度更快,然后另一個狀態回落。function copyButtonClipBrd(index) {  console.log("Test Copy Button");  console.log(cpyBTN);  let newArr = [...cpyBTN];  newArr[index] = "Copied!";  setCpyBTN(newArr);    setTimeout(function () {    let newArr = [...cpyBTN];    newArr[index] = "Copy";    setCpyBTN(newArr);  }, 600);}會喜歡任何建議,甚至更好的方法來做到這一點,因為我這樣做主要是為了學習。謝謝大家!
查看完整描述

4 回答

?
慕桂英546537

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 上查看此演示



查看完整回答
反對 回復 2022-10-21
?
Cats萌萌

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以設置要復制的文本。


除此之外,我們還需要對上一個超時的引用,以便我們可以在觸發下一個項目超時之前清除它。


查看完整回答
反對 回復 2022-10-21
?
慕碼人8056858

TA貢獻1803條經驗 獲得超6個贊

所以我嘗試使用@Agney 建議在 setState 中使用回調。這是codesanbox鏈接https://codesandbox.io/s/quirky-dubinsky-lm03x?file=/src/App.js

所以基本上我們在 setstate 回調中檢查索引以最初將其設置為復制,在超時回調中我們再次檢查相同的索引以設置回復制。


查看完整回答
反對 回復 2022-10-21
?
收到一只叮咚

TA貢獻1821條經驗 獲得超5個贊

這是直接使用狀態對其進行操作的問題,相反,ReactJS 提供了一個回調版本setState,允許您currentState在執行時作為參數訪問 。您可以將其用作:


setCpyBtn((currentState) => {

  return currentState.map((item, i) => {

    if (i === index) {

      return 'Copy';

    }

    return 'Copied';

  });

})

當然反之亦然。


文檔


查看完整回答
反對 回復 2022-10-21
  • 4 回答
  • 0 關注
  • 167 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號