如果我不拥有该代码,如何将 Ref 分配给 React 组件中的按钮?我想集中注意力

How to assign a Ref to a button in a React component if I don't own that code? I want to focus it

我正在研究 React。还有另一个团队向我们展示了一个组件,其中有一个按钮。它是我们存储库的依赖项。我希望在完成特定操作时聚焦该按钮。我想使用 refs 或任何其他可接受的方式来完成。

myCode.js

focusExternalButton() {
  // some code that focuses the button in the external component
}

render() {

  return {
    <div>
      <ExternalButtonComponent/>
      <button onClick={this.focusExternalButton}>submit</button>
    </div>
  }
} 

ExternalButtonComponent.js

render() {
  return <div><button id="btn-external">This is a button</button></div>
}

如何在单击我的按钮时将焦点放在外部按钮上?我正在考虑 refs,但不确定如何实现。

让我有点吃惊的是,外部组件使用 ids,因为在页面中多次呈现它会导致页面上出现重复的 ids,这是无效的 HTML.

尽管如此,是的,您可以直接查询 DOM,尽管我可能会在挂载时执行一次并将结果返回的元素存储在 ref.

const { useEffect, useRef } = React;

function App() {
  const buttonRef = useRef();

  useEffect(() => {
    buttonRef.current = document.getElementById('btn-external');
  }, []);

  function focusExternalButton() {
    buttonRef.current.focus();
  };

  return (
    <div>
      <ExternalButtonComponent label="This is a button" />
      <button type='button' onClick={focusExternalButton}>submit</button>
    </div>
  );
}

function ExternalButtonComponent({label}) {
  return <div><button id="btn-external">{label}</button></div>;
}

ReactDOM.render(
  <App />,
  document.getElementById("root")
);
#btn-external:focus { box-shadow: 0 0 0 3px rgba(21, 156, 228, 0.4);}
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>

<div id="root"></div>

但是,为了避免每次使用该组件时都必须这样做,您可以包装外部组件和 forward the ref

const WrappedExternalButtonComponent = forwardRef((props, ref) => {
  useEffect(() => {
    ref.current = document.getElementById('btn-external');
  }, []);

  return <ExternalButtonComponent {...props} />
});

const { useEffect, useRef, forwardRef } = React;

const WrappedExternalButtonComponent = forwardRef((props, ref) => {
  useEffect(() => {
    ref.current = document.getElementById('btn-external');
  }, []);

  return <ExternalButtonComponent {...props} />
});

function ExternalButtonComponent({label}) {
  return <div><button id="btn-external">{label}</button></div>;
}

function App() {
  const buttonRef = useRef();

  function focusExternalButton() {
    buttonRef.current.focus();
  };

  return (
    <div>
      <WrappedExternalButtonComponent ref={buttonRef} label="This is a button" />
      <button type='button' onClick={focusExternalButton}>submit</button>
    </div>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
#btn-external:focus { box-shadow: 0 0 0 3px rgba(21, 156, 228, 0.4);}
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>

<div id="root"></div>

或者甚至通过创建一个将 Component 和查询函数作为参数和 returns 包装组件的实用程序来进一步概括它。

const wrapExternalComponent = (Component, query) => forwardRef(({ children, ...props }, ref) => {
  useEffect(() => {
    ref.current = query();
  }, []);

  return (
    <Component {...props}>
      {children}
    </Component>
  );
});

const WrappedExternalButtonComponent = 
  wrapExternalComponent(ExternalButtonComponent, () => document.getElementById('btn-external'));

const { useEffect, useRef, forwardRef } = React;

const wrapExternalComponent = (Component, query) => forwardRef(({ children, ...props }, ref) => {
  useEffect(() => {
    ref.current = query();
  }, []);

  return (
    <Component {...props}>
      {children}
    </Component>
  );
});

function ExternalButtonComponent({label}) {
  return <div><button id="btn-external">{label}</button></div>;
}

const WrappedExternalButtonComponent = 
  wrapExternalComponent(ExternalButtonComponent, () => document.getElementById('btn-external'));

function App() {
  const buttonRef = useRef();

  function focusExternalButton() {
    buttonRef.current.focus();
  };

  return (
    <div>
      <WrappedExternalButtonComponent ref={buttonRef} label="This is a button" />
      <button type='button' onClick={focusExternalButton}>submit</button>
    </div>
  );
}





ReactDOM.render(
  <App />,
  document.getElementById('root')
);
#btn-external:focus { box-shadow: 0 0 0 3px rgba(21, 156, 228, 0.4);}
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>

<div id="root"></div>