如何在反应钩子中创建可重用状态?

Posted

技术标签:

【中文标题】如何在反应钩子中创建可重用状态?【英文标题】:how to create reusable state in react hooks? 【发布时间】:2020-11-23 17:59:05 【问题描述】:

我的应用程序中有 5 个按钮,我想根据按钮状态更改背景颜色,所以现在当我单击一个按钮时,它会影响所有按钮,这些按钮用于在 UI 中复制某些内容,每个按钮都复制不同的东西。

注意:我知道我可以为每个按钮创建五个状态,一切都会好起来的,但我认为这是一个糟糕的解决方案。

另外,假设每个都有自己的图标和文本,我们应该可以通过点击按钮将文本更改为COPIED 并更改按钮的图标

喜欢这里。

这是我目前所拥有的

    import React,  useState, useEffect, useRef  from 'react';
    
    function Mata() 
    const [isCopied, setIsCopied] = useState(0);
    
    
        return (
            <div className="container">
                <button style= backgroundColor: isCopied ? '#262626' : '#F3F3F3' className=`btn1 $isCopied && activeTab` onClick=handleBtn1>Copy anything</button>
                <button style= backgroundColor: isCopied ? '#262626' : '#F3F3F3' className=`btn2 $isCopied && activeTab` onClick=handleBtn2>Copy something</button>
                <button style= backgroundColor: isCopied ? '#262626' : '#F3F3F3' className=`btn3 $isCopied && activeTab` onClick=handleBtn3>Copy Imgae</button>
                <button style= backgroundColor: isCopied ? '#262626' : '#F3F3F3' className=`btn4 $isCopied && activeTab` onClick=handleBtn4>Copy text</button>
                <button style= backgroundColor: isCopied ? '#262626' : '#F3F3F3' className=`btn5 $isCopied && activeTab` onClick=handleBtn5>Copy Link</button>
             
            </div>
        )
    
    
    export default Mata

我怎样才能只创建一个状态,例如const[isCopied, setIsCopied] = useState();并在与在 UI 中复制内容相关的任何按钮中使用它?

【问题讨论】:

【参考方案1】:

这里可能有三个不同的答案:

我只会使用文件 useState 调用

由于您说处理程序都是独立的,并且您正在分别编写按钮,所以我只使用五个 useState 调用。简单、清晰,避免按钮之间的串扰。

但你说过你不想那样做,所以回答#2...:-)

使用一组处理程序和一个对象作为标志

(其实我不喜欢下面这个,所以看吧,然后继续看下去。)

您可以将这些函数放在一个数组中,并可能使标志成为由按钮的id 键入的对象,我们可以从索引创建它:

function Mata() 
    const [isCopied, setIsCopied] = useState();

    // ...create handlers...

    const buttonHandlers = [handleBtn1, handleBtn2, handleBtn3, handleBtn4, handleBtn5];

    return (
        <div className="container">
            buttonHandlers.map((handleBtn, index) => 
                const flag = isCopied[index];
                return <button id=index style= backgroundColor: flag ? '#262626' : '#F3F3F3' className=`btn$index+1 $flag && activeTab` onClick=handleBtn>Copy anything</button>;
            )
        </div>
    );

在处理函数内:

function handleBtn1(evt) 
    // ...logic...
    if (/*...need to set the flag...*/) 
        setIsCopied(isCopied => (...isCopied, [evt.target.id]: true));
     else if (/*...need to clear the flag...*/) 
        setIsCopied(isCopied => (...isCopied, [evt.target.id]: true));
    

有人可能会告诉你id 值不能以数字开头。这是不正确的,他们可以。 CSS ID 选择器不能以非转义数字开头,但我们这里没有使用 CSS。

为由按钮的id 键入的标志使用对象

或者完全取消数组,因为它不再给你买太多东西了:

function Mata() 
    const [isCopied, setIsCopied] = useState();

    // ...create handlers...

    return (
        <div className="container">
            <button id="btn1" style= backgroundColor: isCopied.btn1 ? '#262626' : '#F3F3F3' className=`btn1 $isCopied.btn1 && activeTab` onClick=handleBtn1>Copy anything</button>
            <button id="btn2" style= backgroundColor: isCopied.btn2 ? '#262626' : '#F3F3F3' className=`btn2 $isCopied.btn2 && activeTab` onClick=handleBtn2>Copy something</button>
            <button id="btn3" style= backgroundColor: isCopied.btn3 ? '#262626' : '#F3F3F3' className=`btn3 $isCopied.btn3 && activeTab` onClick=handleBtn3>Copy Imgae</button>
            <button id="btn4" style= backgroundColor: isCopied.btn4 ? '#262626' : '#F3F3F3' className=`btn4 $isCopied.btn4 && activeTab` onClick=handleBtn4>Copy text</button>
            <button id="btn5" style= backgroundColor: isCopied.btn5 ? '#262626' : '#F3F3F3' className=`btn5 $isCopied.btn5 && activeTab` onClick=handleBtn5>Copy Link</button>
        </div>
    );

【讨论】:

看起来很棒的解决方案,但有一个问题我有五个函数负责每个按钮操作,因为我写道每个按钮都在做其他事情,那么如何在handlebtn 中传递每个函数?通过开关? @TheDeadMan - 函数是在 Mata 组件中定义的,还是在其他地方定义的? 在 mata 组件中【参考方案2】:

也许创建你自己的 React 组件来封装你的想法,并使用那个组件。

这是一个codesandbox,展示了如何对其进行自定义以满足您的需求,并为每个按钮的 onClick 事件传递一个函数。

下面是一个简单的 sn-p。

import React,  useState  from "react";
import "./styles.css";

export default function App() 
  return (
    <div className="App">
      <ColouredButton title="Copy something" />
      <ColouredButton title="Copy something" />
      <ColouredButton title="Copy Imgae" />
      <ColouredButton title="Copy text" />
      <ColouredButton title="Copy Link" />
    </div>
  );


const ColouredButton = props => 
  const [isCopied, setIsCopied] = useState(0);
  return (
    <button
      style= backgroundColor: isCopied ? "#262626" : "#F3F3F3" 
      className=`btn1 $isCopied && activeTab`
      onClick=() => setIsCopied(prevState => !prevState)
    >
      props.title
    </button>
  );
;

【讨论】:

非常好的解决方案,我的兄弟,Gandzal 假设单击每个按钮,您需要更改文本和图标,如此处ibb.co/m9b0brz,我们如何使用您的解决方案来完成?【参考方案3】:

您可能想尝试useReducer() 挂钩。

如果你之前有使用过redux的经验,你可以很容易理解这个概念。

您可以在此处阅读有关 useReducer 挂钩的更多信息。

https://reactjs.org/docs/hooks-reference.html#usereducer

【讨论】:

到目前为止,我一直在寻找可以快速理解的简化解决方案,但谢谢

以上是关于如何在反应钩子中创建可重用状态?的主要内容,如果未能解决你的问题,请参考以下文章

如何在ktor中创建可重用的拦截器?

如何在JSF中创建可重用的组件?

在Vue中创建可重用的 Transition

在 Google AdWords 中创建可重用函数

在 Swift 中创建可重用视图并添加完成处理程序

如何在反应中使用自定义可重用组件作为输入字段