如何在 React Component 中使用 forwardRef?

How can I use forwardRef in React Component?

有人可以帮助我吗?我正在 React 中创建一个组件,我想使用 forwardRef 使其更易于访问。在我的例子中,我正在制作一个按钮,我正在使用按钮的属性,我还做了一些使它更动态的事情。

这是我的代码摘要。

export interface ButtonProps 
extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
  children?: React.ReactNode;
  loading?: boolean;
}

class Button extends React.Component<ButtonProps> {

  render() {
    const {
      ...otherProps
    } = this.props;

    return (
      <button {...(otherProps)}></button>
    )
  }
}

export default Button;

我试图启动一些东西,但马上就出错了

const ForwardedElement = React.forwardRef<ButtonProps, HTMLButtonElement> (
  (props: ButtonProps, ref) => <Button {...props}/>
)

export default ForwardedElement;

你必须将 ref 传递给 spread 道具:

export interface ButtonProps 
extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
  children?: React.ReactNode;
  loading?: boolean;
  ref?: React.RefObject<HTMLButtonElement>
}

class Button extends React.Component<ButtonProps> {

  render() {
    const {
      ...otherProps,
      ref
    } = this.props;

    return (
      <button {...otherProps} ref={ref}></button>
    )
  }
}

export default Button;

const ForwardedElement = React.forwardRef<ButtonProps, HTMLButtonElement> (
  (props: ButtonProps, ref) => <Button {...props} ref={ref}/>
)

export default ForwardedElement;

现在应该可以了,请参阅

我建议你使用 useImperativeHandle 钩子

useImperativeHandle 自定义在使用 ref 时暴露给 parent 组件的实例值。让我们用一个例子来形象化。

这里有一个组件作为搜索栏

import React, {forwardRef, useImperativeHandle, useRef} from "react";
import {Form} from "reactstrap";

const SearchBar = (props, ref) => {
    const buttonRef = useRef<any>();

    useImperativeHandle(ref, () => ({
        getCurrentValue: () => {
            return buttonRef.current ? buttonRef.current["value"] : '';
        },
        setCurrentValue: (value) => {
            if (buttonRef.current) {
                buttonRef.current["value"] = value;
            }
        }
    }));

  return (
      <Form className="p-3 w-100" onSubmit={(e) => props.onSubmitHandler(e)}>
          <div className="form-group m-0">
              <div className="input-group">
                  <input
                      type="text"
                      className="form-control"
                      placeholder="Search ..."
                      aria-label="Word to be searched"
                      ref={buttonRef}
                  />
                  <div className="input-group-append">
                      <button className="btn btn-primary" type="submit">
                          <i className="mdi mdi-magnify" />
                      </button>
                  </div>
              </div>
          </div>
      </Form>
  );
}

export default forwardRef(SearchBar);

这是我们称之为搜索栏组件的 header 组件

import React, {useEffect, useRef, useState} from 'react';
import SearchBar from '../Form/Search/SearchBar';
import Router from 'next/router';

const Header = () => {
    const mobileSearchRef = useRef<any>();
    const [search, setSearch] = useState<any>(false);

    const codeSearchHandler = (e) => {
        e.preventDefault();

        setSearch(!search);

        if (mobileSearchRef.current) {
            if (mobileSearchRef.current.getCurrentValue() == '') {
                return;
            }
        }

        Router.push({
            pathname: '/search',
            query: {
              searchTerm: mobileSearchRef.current
                  ? mobileSearchRef.current.getCurrentValue()
                  : ''
            },
        });

        mobileSearchRef.current.setCurrentValue('');
    };

    return (
        <React.Fragment>
            <header id="page-topbar">
                <div className="navbar-header">
                    <div className="d-flex">
                        <div className="dropdown d-inline-block d-lg-none ms-2">
                            <button
                                onClick={() => {
                                    setSearch(!search);
                                }}
                                type="button"
                                className="btn header-item noti-icon mt-2"
                                id="page-header-search-dropdown"
                            >
                                <i className="mdi mdi-magnify" />
                            </button>
                            <div
                                className={
                                    search
                                    ? 'dropdown-menu dropdown-menu-lg dropdown-menu-end p-0 show'
                                    : 'dropdown-menu dropdown-menu-lg dropdown-menu-end p-0'
                                }
                                aria-labelledby="page-header-search-dropdown"
                            >
                                <SearchBar
                                    id="headerSearchBar"
                                    ref={mobileSearchRef}
                                    onSubmitHandler={(e) => codeSearchHandler(e)}
                                />
                            </div>
                        </div>
                    </div>
                </div>
            </header>
        </React.Fragment>
    );
};

export default Header;

如果我们查看 header 组件,我们可以看到我们使用 mobileSearchRef 和 getCurrentValue 方法获取搜索栏组件的输入值。我们也可以使用 setCurrentValue 方法设置它的值。