是否可以公开 React 函数组件中定义的函数以在其他组件中调用?

发布于 2025-01-15 00:08:39 字数 1725 浏览 1 评论 0原文

我正在重构警报小部件的一些旧代码,并将其抽象为使用 DOM 门户和条件渲染的自己的组件。我希望尽可能多地保留该组件内部的工作,因此理想情况下,我希望能够公开 Alert 组件本身以及该组件内部定义的函数来触发渲染状态和样式动画这样就不需要外部状态管理。我想要做的事情是这样的:

import Alert, { renderAlert } from '../Alert'

const CopyButton = () => (
  <>
    <Alert text="Text copied!" />
    <button onClick={() => renderAlert()}>Copy Your Text</button>
  </>
)

这是我目前为 Alert 组件所做的事情 - 现在它从外部接收一个状态变量,当单击按钮时该状态变量会翻转并触发 useEffect 在 Alert 内部触发 renderAlert 函数。我希望直接从组件公开 renderAlert ,这样我就可以调用它,而无需像上面那样使用额外的状态变量。

const Alert = ({ label, color, stateTrigger }) => {
  const { Alert__Container, Alert, open } = styles;

  const [alertVisible, setAlertVisible] = useState<boolean>(false);
  const [alertRendered, setAlertRendered] = useState<boolean>(false);

  const portalElement = document.getElementById('portal');

  const renderAlert = (): void => {
    setAlertRendered(false);
    setAlertVisible(false);

    setTimeout(() => {
      setAlertVisible(true);
    }, 5);
    setAlertRendered(true);

    setTimeout(() => {
      setTimeout(() => {
        setAlertRendered(false);
      }, 251);
      setAlertVisible(false);
    }, 3000);
  };

  useEffect(() => {
    renderAlert();
  }, [stateTrigger])

  const ele = (
    <div className={Alert__Container}>
      { alertRendered && (
        <div className={`${Alert} ${alertVisible ? open : ''}`}>
          <DesignLibAlert label={label} color={color}/>
        </div>
      )}
    </div>
  );

  return portalElement
    ? ReactDOM.createPortal(ele, portalElement) : null;
};

export default Alert;

I'm refactoring some old code for an alert widget and am abstracting it into its own component that uses DOM portals and conditional rendering. I want to keep as much of the work inside of this component as I possibly can, so ideally I'd love to be able to expose the Alert component itself as well as a function defined inside of that component triggers the render state and style animations so that no outside state management is required. Something like this is what I'm looking to do:

import Alert, { renderAlert } from '../Alert'

const CopyButton = () => (
  <>
    <Alert text="Text copied!" />
    <button onClick={() => renderAlert()}>Copy Your Text</button>
  </>
)

Here's what I currently have for the Alert component - right now it takes in a state variable from outside that just flips when the button is clicked and triggers the useEffect inside of the Alert to trigger the renderAlert function. I'd love to just expose renderAlert directly from the component so I can call it without the additional state variable like above.

const Alert = ({ label, color, stateTrigger }) => {
  const { Alert__Container, Alert, open } = styles;

  const [alertVisible, setAlertVisible] = useState<boolean>(false);
  const [alertRendered, setAlertRendered] = useState<boolean>(false);

  const portalElement = document.getElementById('portal');

  const renderAlert = (): void => {
    setAlertRendered(false);
    setAlertVisible(false);

    setTimeout(() => {
      setAlertVisible(true);
    }, 5);
    setAlertRendered(true);

    setTimeout(() => {
      setTimeout(() => {
        setAlertRendered(false);
      }, 251);
      setAlertVisible(false);
    }, 3000);
  };

  useEffect(() => {
    renderAlert();
  }, [stateTrigger])

  const ele = (
    <div className={Alert__Container}>
      { alertRendered && (
        <div className={`${Alert} ${alertVisible ? open : ''}`}>
          <DesignLibAlert label={label} color={color}/>
        </div>
      )}
    </div>
  );

  return portalElement
    ? ReactDOM.createPortal(ele, portalElement) : null;
};

export default Alert;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

说好的呢 2025-01-22 00:08:39

尽管“访问”其他组件并调用函数并不常见,但 React 确实允许“后门”这样做。

这个想法是强制公开 renderAlert 函数通过 React 参考系统。

示例:

import { forwardRef, useImperativeHandle } from 'react';

const Alert = forwardRef(({ label, color, stateTrigger }, ref) => {
  const { Alert__Container, Alert, open } = styles;

  const [alertVisible, setAlertVisible] = useState<boolean>(false);
  const [alertRendered, setAlertRendered] = useState<boolean>(false);

  const portalElement = document.getElementById('portal');

  const renderAlert = (): void => {
    setAlertRendered(false);
    setAlertVisible(false);

    setTimeout(() => {
      setAlertVisible(true);
    }, 5);
    setAlertRendered(true);

    setTimeout(() => {
      setTimeout(() => {
        setAlertRendered(false);
      }, 251);
      setAlertVisible(false);
    }, 3000);
  };

  useEffect(() => {
    renderAlert();
  }, [stateTrigger]);

  useImperativeHandle(ref, () => ({
    renderAlert,
  }));

  const ele = (
    <div className={Alert__Container}>
      { alertRendered && (
        <div className={`${Alert} ${alertVisible ? open : ''}`}>
          <DesignLibAlert label={label} color={color}/>
        </div>
      )}
    </div>
  );

  return portalElement
    ? ReactDOM.createPortal(ele, portalElement) : null;
});

export default Alert;

...

import { useRef } from 'react';
import Alert from '../Alert'

const CopyButton = () => {
  const ref = useRef();

  const clickHandler = () => {
    ref.current?.renderAlert();
  };

  return (
    <>
      <Alert ref={ref} text="Text copied!" />
      <button onClick={clickHandler}>Copy Your Text</button>
    </>
  )
};

编辑 is-it-possible-to-expose-a-function-define-within-a-react-function-component -to

实现此目的的一种更 React 的方式可能是将 Alert 状态抽象到一个 AlertProvider 中,该 AlertProvider 呈现门户并处理警报的呈现,并通过以下方式提供 renderAlert 函数:这 语境。

示例:

import { createContext, useContext, useState } from "react";

interface I_Alert {
  renderAlert: (text: string) => void;
}

const AlertContext = createContext<I_Alert>({
  renderAlert: () => {}
});

const useAlert = () => useContext(AlertContext);

const AlertProvider = ({ children }: { children: React.ReactElement }) => {
  const [text, setText] = useState<string>("");
  const [alertVisible, setAlertVisible] = useState<boolean>(false);
  const [alertRendered, setAlertRendered] = useState<boolean>(false);

  ...

  const renderAlert = (text: string): void => {
    setAlertRendered(false);
    setAlertVisible(false);
    setText(text);

    setTimeout(() => {
      setAlertVisible(true);
    }, 5);
    setAlertRendered(true);

    setTimeout(() => {
      setTimeout(() => {
        setAlertRendered(false);
      }, 251);
      setAlertVisible(false);
    }, 3000);
  };

  const ele = <div>{alertRendered && <div> ..... </div>}</div>;

  return (
    <AlertContext.Provider value={{ renderAlert }}>
      {children}
      // ... portal ...
    </AlertContext.Provider>
  );
};

...

const CopyButton = () => {
  const { renderAlert } = useAlert();

  const clickHandler = () => {
    renderAlert("Text copied!");
  };

  return (
    <>
      <button onClick={clickHandler}>Copy Your Text</button>
    </>
  );
};

...

function App() {
  return (
    <AlertProvider>
      ...
      <div className="App">
        ...
        <CopyButton />
        ...
      </div>
      ...
    </AlertProvider>
  );
}

编辑 is-it-possible-to-expose-a-function-define-within-a-react-function-component -to(分叉)

Though it's not common to "reach" into other components and invoke functions, React does allow a "backdoor" to do so.

The idea is to expose out the renderAlert function imperatively via the React ref system.

Example:

import { forwardRef, useImperativeHandle } from 'react';

const Alert = forwardRef(({ label, color, stateTrigger }, ref) => {
  const { Alert__Container, Alert, open } = styles;

  const [alertVisible, setAlertVisible] = useState<boolean>(false);
  const [alertRendered, setAlertRendered] = useState<boolean>(false);

  const portalElement = document.getElementById('portal');

  const renderAlert = (): void => {
    setAlertRendered(false);
    setAlertVisible(false);

    setTimeout(() => {
      setAlertVisible(true);
    }, 5);
    setAlertRendered(true);

    setTimeout(() => {
      setTimeout(() => {
        setAlertRendered(false);
      }, 251);
      setAlertVisible(false);
    }, 3000);
  };

  useEffect(() => {
    renderAlert();
  }, [stateTrigger]);

  useImperativeHandle(ref, () => ({
    renderAlert,
  }));

  const ele = (
    <div className={Alert__Container}>
      { alertRendered && (
        <div className={`${Alert} ${alertVisible ? open : ''}`}>
          <DesignLibAlert label={label} color={color}/>
        </div>
      )}
    </div>
  );

  return portalElement
    ? ReactDOM.createPortal(ele, portalElement) : null;
});

export default Alert;

...

import { useRef } from 'react';
import Alert from '../Alert'

const CopyButton = () => {
  const ref = useRef();

  const clickHandler = () => {
    ref.current?.renderAlert();
  };

  return (
    <>
      <Alert ref={ref} text="Text copied!" />
      <button onClick={clickHandler}>Copy Your Text</button>
    </>
  )
};

Edit is-it-possible-to-expose-a-function-defined-within-a-react-function-component-to

A more React-way to accomplish this might be to abstract the Alert state into an AlertProvider that renders the portal and handles the rendering of the alert and provides the renderAlert function via the context.

Example:

import { createContext, useContext, useState } from "react";

interface I_Alert {
  renderAlert: (text: string) => void;
}

const AlertContext = createContext<I_Alert>({
  renderAlert: () => {}
});

const useAlert = () => useContext(AlertContext);

const AlertProvider = ({ children }: { children: React.ReactElement }) => {
  const [text, setText] = useState<string>("");
  const [alertVisible, setAlertVisible] = useState<boolean>(false);
  const [alertRendered, setAlertRendered] = useState<boolean>(false);

  ...

  const renderAlert = (text: string): void => {
    setAlertRendered(false);
    setAlertVisible(false);
    setText(text);

    setTimeout(() => {
      setAlertVisible(true);
    }, 5);
    setAlertRendered(true);

    setTimeout(() => {
      setTimeout(() => {
        setAlertRendered(false);
      }, 251);
      setAlertVisible(false);
    }, 3000);
  };

  const ele = <div>{alertRendered && <div> ..... </div>}</div>;

  return (
    <AlertContext.Provider value={{ renderAlert }}>
      {children}
      // ... portal ...
    </AlertContext.Provider>
  );
};

...

const CopyButton = () => {
  const { renderAlert } = useAlert();

  const clickHandler = () => {
    renderAlert("Text copied!");
  };

  return (
    <>
      <button onClick={clickHandler}>Copy Your Text</button>
    </>
  );
};

...

function App() {
  return (
    <AlertProvider>
      ...
      <div className="App">
        ...
        <CopyButton />
        ...
      </div>
      ...
    </AlertProvider>
  );
}

Edit is-it-possible-to-expose-a-function-defined-within-a-react-function-component-to (forked)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文