reactjs 当使用react-router-dom时,如何避免“无法为函数组件提供引用”?

xcitsw88  于 2023-01-12  发布在  React
关注(0)|答案(9)|浏览(173)

我有以下内容(使用材质UI)....

import React from "react";
import { NavLink } from "react-router-dom";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
function LinkTab(link){
    return <Tab component={NavLink}
        to={link.link}
        label={link.label}
        value={link.link}
        key={link.link}
    />;
}

在新版本中,这会导致以下警告...
警告:无法为函数组件提供引用。访问此引用的尝试将失败。是否要使用React.forwardRef()?
检查NavLink中ForwardRef .的渲染方法(由ForwardRef创建)
我试着换...

function LinkTab(link){
    // See https://material-ui.com/guides/composition/#caveat-with-refs
    const MyLink = React.forwardRef((props, ref) => <NavLink {...props} ref={ref} />);
    return <Tab component={MyLink}
        to={link.link}
        label={link.label}
        value={link.link}
        key={link.link}
    />;
}

但我还是收到了警告。我该如何解决这个问题?

qni6mghb

qni6mghb1#

把它写成innerRef

// Client.js
<Input innerRef={inputRef} />

将其用作ref

// Input.js
const Input = ({ innerRef }) => {
  return (
    <div>
      <input ref={innerRef} />
    </div>
  )
}
csbfibhn

csbfibhn2#

来自react-routerNavLinkLink的专用版本的函数组件,其公开了用于该目的的innerRef属性。

// required for react-router-dom < 6.0.0
// see https://github.com/ReactTraining/react-router/issues/6056#issuecomment-435524678
const MyLink = React.forwardRef((props, ref) => <NavLink innerRef={ref} {...props} />);

您还可以在我们的文档中搜索react-router,然后转到https://mui.com/getting-started/faq/#how-do-i-use-react-router,该链接指向https://mui.com/components/buttons/#third-party-routing-library。最后一个链接提供了一个工作示例,并解释了这一点在react-router v6中可能会发生的变化

h5qlskok

h5qlskok3#

您可以使用refs代替ref。这只在避免特殊的 prop 名称ref时才起作用。

<InputText
  label="Phone Number"
  name="phoneNumber"
  refs={register({ required: true })}
  error={errors.phoneNumber ? true : false}
  icon={MailIcon}
/>
igsr9ssn

igsr9ssn4#

如果您发现无法向组件添加自定义的ref prop或forwardRef,我有一个技巧,仍然可以为您的功能组件获取ref对象。
假设您想将ref添加到一个定制功能组件,例如:

const ref = useRef();

 //throws error as Button is a functional component without ref prop
 return <Button ref={ref}>Hi</Button>;

你可以把它 Package 在一个通用的html元素中,并在上面设置ref

const ref = useRef();

 // This ref works. To get button html element inside div, you can do 
 const buttonRef = ref.current && ref.current.children[0];
 return (
  <div ref={ref}>
   <Button>Hi</Button>
  </div>
 );

当然,要相应地管理状态,并在何处使用buttonRef对象。

ctehm74n

ctehm74n5#

在我们的例子中,我们将一个SVG组件(站点的徽标)直接传递给NextJS的Link Component,这是一个有点定制的组件,我们得到了这样的错误。
使用SVG的标头组件是问题的“原因”。

import Logo from '_public/logos/logo.svg'
import Link from '_components/link/Link'

const Header = () => (
  <div className={s.headerLogo}>
    <Link href={'/'}>
      <Logo /> 
    </Link>
  </div>
)

控制台上的错误消息

Function components cannot be given refs. Attempts to access this ref will fail.
Did you mean to use React.forwardRef()?

自定义链接组件

import NextLink from 'next/link'
import { forwardRef } from 'react'

const Link = ({ href, shallow, replace, children, passHref, className }, ref) => {
  return href ? (
    <NextLink
      href={href}
      passHref={passHref}
      scroll={false}
      shallow={shallow}
      replace={replace}
      prefetch={false}
      className={className}
    >
      {children}
    </NextLink>
  ) : (
    <div className={className}>{children}</div>
  )
}

export default forwardRef(Link)

现在,我们确保在自定义的链接组件中使用forwardRef,但仍然得到该错误。
为了解决这个问题,我将SVG元素的 Package 器定位改为this和 :poof:

const Header = () => (
  <Link href={'/'}>
    <div className={s.headerLogo}>
      <Logo />
    </div>
 </Link>
)
vsikbqxv

vsikbqxv6#

要修正这个警告,你应该用forwardRef函数 Package 你的定制组件,就像blog中提到的那样

const AppTextField =(props) {return(/*your component*/)}

将上面的代码更改为

const AppTextField = forwardRef((props,ref) {return(/*your component*/)}
5t7ly7z5

5t7ly7z57#

const renderItem = ({ item, index }) => {

        return (
            <>          
            <Item
                key={item.Id}
                item={item}
                index={index}
            />
            </>
        );
    };

使用片段求解React.forwardRef()?警告

qoefvg9y

qoefvg9y8#

如果你正在使用函数组件,那么React.forwardRef是一个非常好的特性,可以让你知道如何在这样的场景中使用它。如果阅读这篇文章的人是更多的动手类型,我就提供了一个codesandbox供你使用。有时它最初并不加载样式化组件,所以当沙箱加载时,你可能需要刷新内联浏览器。
https://codesandbox.io/s/react-forwardref-example-15ql9t?file=/src/App.tsx

// MyAwesomeInput.tsx
import React from "react";
import { TextInput, TextInputProps } from "react-native";
import styled from "styled-components/native";

const Wrapper = styled.View`
  width: 100%;
  padding-bottom: 10px;
`;

const InputStyled = styled.TextInput`
  width: 100%;
  height: 50px;
  border: 1px solid grey;
  text-indent: 5px;
`;

// Created an interface to extend the TextInputProps, allowing access to all of its properties
// from the object that is created from Styled-Components.
//
// I also define the type that the forwarded ref will be.
interface AwesomeInputProps extends TextInputProps {
  someProp?: boolean;
  ref?: React.Ref<TextInput>;
}

// Created the functional component with the prop type created above.
//
// Notice the end of the line, where you wrap everything in the React.forwardRef(). 
// This makes it take one more parameter, called ref. I showed what it looks like
// if you are a fan of destructuring.
const MyAwesomeInput: React.FC<AwesomeInputProps> = React.forwardRef( // <-- This wraps the entire component, starting here.
  ({ someProp, ...props }, ref) => {
    return (
      <Wrapper>
        <InputStyled {...props} ref={ref} />
      </Wrapper>
    );
  }); // <-- And ending down here.

export default MyAwesomeInput;

然后在调用屏幕上,创建ref变量并将其传递到组件的ref字段。

// App.tsx
import React from "react";
import { StyleSheet, Text, TextInput, View } from "react-native";
import MyAwesomeInput from "./Components/MyAwesomeInput";

const App: React.FC = () => {
  // Set some state fields for the inputs.
  const [field1, setField1] = React.useState("");
  const [field2, setField2] = React.useState("");

  // Created the ref variable that we'll use down below.
  const field2Ref = React.useRef<TextInput>(null);

  return (
    <View style={styles.app}>
      <Text>React.forwardRef Example</Text>
      <View>
        <MyAwesomeInput
          value={field1}
          onChangeText={setField1}
          placeholder="field 1"
          // When you're done typing in this field, and you hit enter or click next on a phone,
          // this makes it focus the Ref field.
          onSubmitEditing={() => {
            field2Ref.current.focus();
          }}
        />
        <MyAwesomeInput
          // Pass the ref variable that's created above to the MyAwesomeInput field of choice.
          // Everything should work if you have it setup right.
          ref={field2Ref}
          value={field2}
          onChangeText={setField2}
          placeholder="field 2"
        />
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  app: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center"
  }
});

export default App;

就是这么简单!不管你把MyAwesomeInput组件放在哪里,你都可以使用一个ref。

enxuqcxy

enxuqcxy9#

我只是在这里粘贴skychavda解决方案,因为它提供了一个引用到一个孩子:因此您可以直接从父方法调用子方法或子引用,而不需要任何警告。
来源:https://github.com/reactjs/reactjs.org/issues/2120

/* Child.jsx */
import React from 'react'

class Child extends React.Component {
  componentDidMount() {
    const { childRef } = this.props;
    childRef(this);
  }
  componentWillUnmount() {
   const { childRef } = this.props;
    childRef(undefined);
  }
  alertMessage() {
    window.alert('called from parent component');
  }
  render() {
    return <h1>Hello World!</h1>
  }
}

export default Child;
/* Parent.jsx */
import React from 'react';
import Child from './Child';

class Parent extends React.Component {
  onClick = () => {
    this.child.alertMessage(); // do stuff
  }
  render() {
    return (
      <div>
        <Child childRef={ref => (this.child = ref)} />
        <button onClick={this.onClick}>Child.alertMessage()</button>
      </div>
    );
  }
}

相关问题