如何更改保存在反应组件的 useRef 对象中的按钮的 onClick 功能?

Posted

技术标签:

【中文标题】如何更改保存在反应组件的 useRef 对象中的按钮的 onClick 功能?【英文标题】:How can I change the onClick function of a button saved in a useRef object in a react component? 【发布时间】:2021-08-10 01:36:47 【问题描述】:

我正在学习 React 中的状态和挂钩。我正在做一个练习,使用deckofcardsAPI 从一副牌中发牌,这不是互联网上最重要的代码,但它确实带来了一个问题。事实上,这甚至不是练习的一部分,我只是很想做。

我有一个存储在useRef 对象中的按钮。我真的很想更改 onClick 函数,但我不知道该怎么做。

import React,  useState, useEffect, useRef  from "react";
import axios from 'axios';

// auto dealer, 1 card/s turned on or off

function CardTable2() 

    const [src, setSrc] = useState('');
    const deckId = useRef();
    const remaining = useRef(52);
    const isDealing = useRef(false);
    const timerId = useRef();
    const button = useRef();

    useEffect(() => 
        timerId.current = setInterval(() => 
            if (isDealing.current) 
                dealCard();
            ;
        , 1000);

        async function createDeck() 
            const res = await axios.get(`http://deckofcardsapi.com/api/deck/new/shuffle/?deck_count=1`);
            deckId.current = res.data.deck_id;
        ;
        createDeck();

        return () =>  clearInterval(timerId.current) 
    , []);

    async function dealCard() 
        if (remaining.current === 0) 
            alert('You are out of cards');
            isDealing.current = false;
            button.current.innerText = "Shuffle deck";
            button.current.onClick = shuffleDeck;
            return;
        
        console.log(button);
        const res = await axios.get(`http://deckofcardsapi.com/api/deck/$deckId.current/draw/?count=1`);
        remaining.current = res.data.remaining;
        setSrc(res.data.cards[0].image);
    ;

    async function shuffleDeck() 
        const res = await axios.get(`http://deckofcardsapi.com/api/deck/$deckId.current/shuffle/`);
        setSrc('');
        button.current.innerText = "Start dealing cards";
        button.current.onClick = toggleDealing;
    

    function toggleDealing() 
        isDealing.current = !isDealing.current;
        button.current.innerText = "Start dealing cards";
    ;


    return (
        <>
            <button onClick=toggleDealing ref=button>isDealing.current ? "Stop dealing cards" : "Start dealing cards"</button>
            <div>
                <img className="CardBox" src=src  />
            </div>
        </>
    )
;

export default CardTable2;

我尝试将button.current.onClick 设置为函数,如上所示,但实际上似乎没有效果。我错过了什么吗?

【问题讨论】:

【参考方案1】:

我认为正在发生的事情是,回报只是每次都退回 toggleDealing。

为什么不去掉 ref 而只用一个通用函数来处理这两种情况?

const [buttonMode, setButtonMode] = useState("shuffle")

function handleClick() 
    if (buttonMode === "deal") 
        deal()
     else if (buttonMode === "shuffle") 
        shuffle()
     

【讨论】:

另外,我不确定这是否应该是 ref const isDealing = useRef(false); 更改 ref 不会导致重新渲染的反应。它就像一个不会触发重新渲染的可变框。但是isDealing 确实会对绘制的内容产生影响吗?所以,我觉得应该是useState(调用set函数会触发重新渲染) 再一次,我还在学习,所以对我来说 useRef 也可以很好地作为一个持久变量,不管重新渲染。我还能用什么(尽量避免使用全局变量,因为那是不是反应方式)。 基本上,考虑的方式是:如果这块状态有渲染含义(认为屏幕上的某些东西在视觉上发生了变化),那么它需要是useState。当我们只想从输入中读取一些值并将其存储在那里以便我们以后可以使用当前属性引用它时(例如我们要调用 api 时),我们经常使用 useRef 将其更改为 state 每次切换时都会导致新的渲染。因此,当我单击开始交易时,它会重新渲染,因此会在此过程中停止。这可能是其他相关问题的原因(我的另一段糟糕的代码),但将其更改为状态会干扰计时器(间隔)。 别担心,祝你好运 :) 还要记住,通过“糟糕的代码”是通往真理的道路。此外,如果您希望您的 useEffect 在状态更改时触发,那么 - 是的 - 将其添加到 useEffect 依赖项数组中。有时我们只希望 useEffect 在状态为 -- 比如说 -- false 时触发。然后我们要做的是在 useEffect 的顶部添加一点“bouncer”逻辑,它会过早返回(即:if (!isSomething) return)

以上是关于如何更改保存在反应组件的 useRef 对象中的按钮的 onClick 功能?的主要内容,如果未能解决你的问题,请参考以下文章

如何解决反应js中的“useRef不是函数错误”

useRef 反应钩子

如何正确更新反应钩子状态中的数组

React Ref 原理理解

React Ref 原理理解

React Ref 原理理解