【问题标题】:how do control the state for multiple component with one function如何用一个功能控制多个组件的状态
【发布时间】:2021-02-05 17:39:39
【问题描述】:

我有一个简单的应用程序,其中包含 3 个相同的按钮,当我单击按钮时,onClick 事件应触发以显示一个 span。现在,我已经使用一个one state 来控制span 是否显示,一旦我点击任何一个按钮,所有span 显示。如何实现代码,所以当我点击按钮时,只有对应的span显示

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

const Popup = (props) => {
  return <span {...props}>xxx</span>;
};

export default function App() {
  const [isOpen, setIsOpen] = useState(true);
  const handleOnClick = () => {
    setIsOpen(!isOpen);
  };
  return (
    <div className="App">
      <button onClick={handleOnClick}> Show popup1</button>
      <Popup hidden={isOpen} />
      <button onClick={handleOnClick}> Show popup2</button>
      <Popup hidden={isOpen} />
      <button onClick={handleOnClick}> Show popup3</button>
      <Popup hidden={isOpen} />
    </div>
  );
}

代码沙盒: https://codesandbox.io/s/cocky-fermi-je8lr?file=/src/App.tsx

【问题讨论】:

    标签: reactjs typescript


    【解决方案1】:

    您应该重新考虑如何使用这些组件。 既然有重复的逻辑和接口,就应该分离到不同的组件中。

    const Popup = (props) => {
      return <span {...props}>xxx</span>;
    };
    
    interface Props {
      buttonText: string
      popupProps?: any
    }
    
    const PopupFC: React.FC<Props> = (props) => {
      const [isOpen, setIsOpen] = useState(false);
    
      return (
        <>
          <button onClick={() => setIsOpen(!isOpen)}>{props.buttonText}</button>
          <Popup hidden={isOpen} {...props.popupProps} />
        </>
      )
    }
    export default function App() {
      const [isOpen, setIsOpen] = useState(true);
      const handleOnClick = () => {
        setIsOpen(!isOpen);
      };
      return (
        <div className="App">
          <PopupFC buttonText="Show popup1" />
          <PopupFC buttonText="Show popup2" />
          <PopupFC buttonText="Show popup3" />
        </div>
      );
    }
    

    【讨论】:

    • 但我想当我点击 PopupFC1 时,弹出消息 Show popup1 然后如果我点击 PopupFC2,则消息 Show popup1 消失然后 Show popup2 弹出
    • 那你应该考虑使用 Context Provider 或者触发父组件的关闭表单
    【解决方案2】:

    如果每个Popup 都需要自己的isOpen 状态,则无法使用单个布尔状态来实现。 也许将按钮和跨度都转换为单个组件并让每个Popup 组件处理自己的isOpen

    import "./styles.css";
    import React, { useState } from "react";
    
    const Popup = (props) => {
      const [isOpen, setIsOpen] = useState(true);
      const handleOnClick = () => {
        setIsOpen(!isOpen);
      };
      return (
        <>
          <button onClick={handleOnClick}>{props.children}</button>
          {isOpen && <span {...props}>xxx</span>}
        </>
      );
    };
    
    export default function App() {
      return (
        <div className="App">
          <Popup>Show popup 1</Popup>
          <Popup>Show popup 2</Popup>
          <Popup>Show popup 3</Popup>
        </div>
      );
    }
    
    

    【讨论】:

      【解决方案3】:

      这仅仅是因为您对所有按钮使用相同的状态“isOpen”, 一旦您单击其中任何一个,它就会反映所有按钮,因为它的值相同。 您可以使用自定义钩子来解决这个问题,因为您重复了逻辑,或者您可以将它们分成小组件

      【讨论】:

        【解决方案4】:

        根据您的评论,您一次只希望打开一个弹出窗口。这在您的原始问题中并不清楚,因此其他答案没有解决这个问题。

        现在您只存储isOpen 的值,即truefalse。那是不够的信息。你怎么知道哪个弹出窗口打开了?

        如果您想一次只显示一个,您可以存储当前打开的弹出窗口的编号或名称(任何类型的唯一 ID)。

        我们将Popup 设为“受控组件”,它不会管理自己的内部isOpen 状态,而是通过props 接收和更新该信息。

        App 组件负责管理打开的弹出窗口并将正确的道具传递给每个Popup 组件。由于我们对多个弹出窗口执行相同的操作,因此我将该逻辑移到了 renderPopup 辅助函数中。

        弹出窗口

        interface PopupProps {
          isOpen: boolean;
          open: () => void;
          close: () => void;
          label: string;
        }
        
        const Popup = ({ isOpen, open, close, label }: PopupProps) => {
          return (
            <>
              <button onClick={open}> Show {label}</button>
              {isOpen && (
                <div>
                  <h1>{label}</h1>
                  <span>xxx</span>
                  <button onClick={close}>Close</button>
                </div>
              )}
            </>
          );
        };
        

        应用

        export default function App() {
          // store the label of the popup which is open,
          // or `null` if all are closed
          const [openId, setOpenId] = useState<string | null>(null);
        
          const renderPopup = (label: string) => {
            return (
              <Popup
                label={label}
                isOpen={openId === label} // check if this popup is the one that's open
                open={() => setOpenId(label)} // open by setting the `openId` to this label
                close={() => setOpenId(null)} // calling `close` closes all
              />
            );
          };
        
          return (
            <div className="App">
              {renderPopup("Popup 1")}
              {renderPopup("Popup 2")}
              {renderPopup("Popup 3")}
            </div>
          );
        }
        

        Code Sandbox

        【讨论】:

          猜你喜欢
          • 2021-12-06
          • 1970-01-01
          • 2020-12-27
          • 2020-11-19
          • 2021-02-16
          • 2021-06-15
          • 1970-01-01
          • 2018-01-13
          • 1970-01-01
          相关资源
          最近更新 更多