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

时间:2020-06-02 05:09:59

标签: javascript reactjs

我正在尝试多次传递孩子的孩子的裁判,但它不起作用。我有一个名为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 个答案:

答案 0 :(得分:1)

对于功能组件,必须使用useRef而不是React.createRef,因为将在render中创建新的ref实例。

如果您使用React.createRef,请利用useMemo记住参考

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"/>

答案 1 :(得分:0)

尝试这个。

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>
    )
});