如何使用 refs React 数组将 ref 传递给孩子的孩子?

IT技术 javascript reactjs
2021-05-10 20:06:01

我试图将多次引用传递给孩子的孩子,但它不起作用。我有一个称为AvatarBuilder使用该Avatars组件的功能组件。此组件呈现Avatar组件列表这个想法是对AvatarBuilder每个Avatar组件进行引用

以下是总结的代码片段:

const AvatarBuilder = props => {
    ...
    // in this dummy example i would have 5 avatars
    const URLS=[1,2,3,4,5];
    const refs = URLS.map(item => ({ ref: React.createRef() }));
    return (
        <>
            <Avatars
                ref={refs}
                urlList={URLS}
            />
        </>
    );

const Avatars = React.forwardRef((props, ref) => {
    let urlList = props.urlList.map((url, index) => {
        return (
            <Avatar
                ref={ref[index].ref}
                url={url}
            />
        )
    })
    return (
        <ul className="Avatars" >
            {urlList}
        </ul>
    )
});

const Avatar = React.forwardRef((props, ref) => {
    return (
        <li className="Avatar">
            <img
                src={props.url}
                ref={ref}
            />
        </li>
    )
});

我收到以下警告,并且在安装所有组件后 refs 数组未更新。

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

Check the render method of `ForwardRef`.
    in h (at Avatar.js:11)
    in li (at Avatar.js:10)
    in ForwardRef (at Avatars.js:10)
    in ul (at Avatars.js:24)
    in ForwardRef (at AvatarBuilder.js:189)
    in AvatarBuilder (at App.js:19)
    in div (at App.js:14)
    in App (at src/index.js:9)
    in StrictMode (at src/index.js:8)

知道这应该如何解决吗?谢谢!

2个回答

对于功能组件,您必须使用 useRef 而不是 React.createRef 因为将在渲染中创建一个新的 refs 实例。

如果你使用 React.createRef,那么使用 useMemo 来记住 refs

const AvatarBuilder = props => {
    // in this dummy example i would have 5 avatars
    const URLS=[1,2,3,4,5];
    const refs = React.useMemo(() =>URLS.map(item => ({ ref: React.createRef() })), []); // create refs only once
    React.useEffect(() => {
       console.log(refs);
    },[])
    return (
            <Avatars
                ref={refs}
                urlList={URLS}
            />
    );
}
const Avatars = React.forwardRef((props, ref) => {
    let urlList = props.urlList.map((url, index) => {
        return (
            <Avatar
                ref={ref[index].ref}
                url={url}
            />
        )
    })
    return (
        <ul className="Avatars" >
            {urlList}
        </ul>
    )
});

const Avatar = React.forwardRef((props, ref) => {
    return (
        <li className="Avatar">
            <img
                src={props.url}
                ref={ref}
            />
        </li>
    )
});

ReactDOM.render(<AvatarBuilder/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app"/>

试试这个。

const AvatarBuilder = props => {
    ...
    // in this dummy example i would have 5 avatars
    const URLS=[1,2,3,4,5];
    const refs = URLS.map(item => React.createRef());
    return (
        <>
            <Avatars
                refs={refs}
                urlList={URLS}
            />
        </>
    );

// you don't need to make it with `fowardRef()`
const Avatars = (props) => {
    const {refs} = props;
    let urlList = props.urlList.map((url, index) => {
        console.log(url, index, typeof (index), ref);
        return (
            <Avatar
                ref={refs[index]}
                url={url}
            />
        )
    })
    return (
        <ul className="Avatars" >
            {urlList}
        </ul>
    )
};

const Avatar = React.forwardRef((props, ref) => {
    return (
        <li className="Avatar">
            <img
                src={props.url}
                ref={ref}
            />
        </li>
    )
});