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

扎克·凯格勒

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

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

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

这是我目前为 Alert 组件所拥有的 - 现在它从外部接收一个状态变量,当单击按钮时它会翻转并触发useEffectAlert 的内部以触发该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;
德鲁里斯

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

renderAlert这个想法是通过 React ref 系统命令式地公开函数。

例子:

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-defined-within-a-react-function-component-to

实现这一点的更 React 方式可能是将 Alert 状态抽象为 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-defined-within-a-react-function-component-to (fork)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

在React无状态组件中定义函数可以吗?

React从其他组件调用函数

如何使我的 axios 函数可在其他 React/Typescript 组件中重用?

在既不是 React 函数组件也不是自定义 React Hook 函数的函数中调用 React Hook “useAxios”

React Hook 在既不是 React 函数组件也不是自定义 React Hook 函数的函数中调用

React Hook "useState" 不能在类组件中调用。React Hooks 必须在 React 函数组件或自定义 React Hook 函数中调用

React:我可以按需从类组件调用函数组件吗?

是否可以创建react组件并在其他项目html中使用它?

如何在React函数组件中调用API?

如何检查组件prop是否是React中的函数?

是否可以将React组件存储在数组中?

在React的子组件中调用父函数

从子组件调用 React 中的函数

在React Native外部组件中调用函数

如何从React组件中调用Firebase函数

React-类中的自定义函数可以拆分为其他文件吗?

在函数“ onSubmit”中调用React Hook,该函数既不是React函数组件也不是自定义的React Hook函数

在函数“ appBar”中调用React Hook“ useStyles”,该函数既不是React函数组件也不是自定义的React Hook函数

是否可以在不使用箭头函数的情况下使用TypeScript键入React函数组件?

无法从 React 中的子组件调用父组件函数

将引用其他函数的函数传递给 React 中的子组件

在函数“ shoes”中调用React Hook“ useEffect”,该函数既不是React函数组件也不是自定义React Hook

在函数“ deviceStatus”中调用React Hook“ useState”,该函数既不是React函数组件也不是自定义React

在函数“ app”中调用React Hook“ useState”,该函数既不是React函数组件也不是自定义React

我可以将类基础组件放在函数基础组件中以使用 React 钩子吗?

为什么React类组件始终需要在其构造函数中调用super(props)?

从函数调用 React 组件

是否可以使用 ref 访问数组映射函数内的 React 组件?

React:是否可以在没有 useState 的情况下制作函数组件?